INT-764 The 'selector' attribute is now supported on the <inbound-channel-adapter/>, <message-driven-channel-adapter/>, and <inbound-gateway/> elements within the JMS namespace. Any valid JMS Message selector expression may be provided.

This commit is contained in:
Mark Fisher
2009-09-04 21:16:52 +00:00
parent d8e7f399e9
commit a3f029695d
11 changed files with 181 additions and 13 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@@ -37,6 +37,8 @@ public class JmsDestinationPollingSource extends AbstractJmsTemplateBasedAdapter
private volatile boolean extractPayload = true;
private volatile String messageSelector;
public JmsDestinationPollingSource(JmsTemplate jmsTemplate) {
super(jmsTemplate);
@@ -51,6 +53,13 @@ public class JmsDestinationPollingSource extends AbstractJmsTemplateBasedAdapter
}
/**
* Specify a JMS Message Selector expression to use when receiving Messages.
*/
public void setMessageSelector(String messageSelector) {
this.messageSelector = messageSelector;
}
/**
* Specify whether the payload should be extracted from each received JMS
* Message to be used as the Spring Integration Message payload.
@@ -65,7 +74,7 @@ public class JmsDestinationPollingSource extends AbstractJmsTemplateBasedAdapter
@SuppressWarnings("unchecked")
public Message<Object> receive() {
Object receivedObject = this.getJmsTemplate().receiveAndConvert();
Object receivedObject = this.getJmsTemplate().receiveSelectedAndConvert(this.messageSelector);
if (receivedObject == null) {
return null;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@@ -78,6 +78,7 @@ public class JmsInboundChannelAdapterParser extends AbstractPollingInboundChanne
if (StringUtils.hasText(headerMapper)) {
builder.addPropertyReference(JmsAdapterParserUtils.HEADER_MAPPER_PROPERTY, headerMapper);
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "selector", "messageSelector");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "extract-payload");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "destination-resolver");
return BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry());

View File

@@ -46,7 +46,7 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
JmsAdapterParserUtils.DESTINATION_NAME_ATTRIBUTE,
"destination-resolver", "transaction-manager", "pub-sub-domain",
"concurrent-consumers", "max-concurrent-consumers",
"max-messages-per-task", "idle-task-execution-limit"
"max-messages-per-task", "idle-task-execution-limit", "selector"
};
@@ -123,6 +123,7 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "destination-resolver");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "transaction-manager");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "pub-sub-domain");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "selector", "messageSelector");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "concurrent-consumers");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "max-concurrent-consumers");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "max-messages-per-task");

View File

@@ -433,6 +433,13 @@
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="selector" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
A JMS Message Selector expression.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2009 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.
@@ -28,9 +28,12 @@ public class StubConsumer implements MessageConsumer {
private String messageText;
private String messageSelector;
public StubConsumer(String messageText) {
public StubConsumer(String messageText, String messageSelector) {
this.messageText = messageText;
this.messageSelector = messageSelector;
}
@@ -42,12 +45,16 @@ public class StubConsumer implements MessageConsumer {
}
public String getMessageSelector() throws JMSException {
return null;
return this.messageSelector;
}
public Message receive() throws JMSException {
StubTextMessage message = new StubTextMessage();
message.setText(this.messageText);
String text = this.messageText;
if (this.messageSelector != null) {
text += " [with selector: " + this.messageSelector + "]";
}
message.setText(text);
return message;
}

View File

@@ -69,16 +69,16 @@ public class StubSession implements Session {
}
public MessageConsumer createConsumer(Destination destination) throws JMSException {
return new StubConsumer(this.messageText);
return new StubConsumer(this.messageText, null);
}
public MessageConsumer createConsumer(Destination destination, String messageSelector) throws JMSException {
return new StubConsumer(this.messageText);
return new StubConsumer(this.messageText, messageSelector);
}
public MessageConsumer createConsumer(Destination destination, String messageSelector, boolean NoLocal)
throws JMSException {
return new StubConsumer(this.messageText);
return new StubConsumer(this.messageText, messageSelector);
}
public TopicSubscriber createDurableSubscriber(Topic topic, String name) throws JMSException {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@@ -128,4 +128,14 @@ public class JmsInboundChannelAdapterParserTests {
assertEquals(new Integer(123), message.getHeaders().get("testAttribute"));
}
@Test
public void adapterWithMessageSelector() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsInboundWithMessageSelector.xml", this.getClass());
PollableChannel output = (PollableChannel) context.getBean("output1");
Message<?> message = output.receive(timeoutOnReceive);
assertNotNull("message should not be null", message);
assertEquals("test [with selector: TestProperty = 'foo']", message.getPayload());
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@@ -249,4 +249,17 @@ public class JmsInboundGatewayParserTests {
gateway.stop();
}
@Test
public void testGatewayWithMessageSelector() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"inboundGatewayWithMessageSelector.xml", this.getClass());
JmsMessageDrivenEndpoint gateway = (JmsMessageDrivenEndpoint) context.getBean("gatewayWithMessageSelector");
gateway.start();
AbstractMessageListenerContainer container = (AbstractMessageListenerContainer)
new DirectFieldAccessor(gateway).getPropertyValue("listenerContainer");
String messageSelector = (String) new DirectFieldAccessor(container).getPropertyValue("messageSelector");
assertEquals("TestProperty = 'foo'", messageSelector);
gateway.stop();
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2002-2009 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.jms.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.channel.PollableChannel;
import org.springframework.integration.core.Message;
/**
* @author Mark Fisher
*/
public class JmsMessageDrivenChannelAdapterParserTests {
long timeoutOnReceive = 3000;
@Test
public void adapterWithMessageSelector() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsInboundWithMessageSelector.xml", this.getClass());
PollableChannel output = (PollableChannel) context.getBean("output2");
Message<?> message = output.receive(timeoutOnReceive);
assertNotNull("message should not be null", message);
assertEquals("test [with selector: TestProperty = 'foo']", message.getPayload());
}
}

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:si="http://www.springframework.org/schema/integration"
xmlns:jms="http://www.springframework.org/schema/integration/jms"
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
http://www.springframework.org/schema/integration/jms
http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd">
<si:channel id="requestChannel">
<si:queue/>
</si:channel>
<jms:inbound-gateway id="gatewayWithMessageSelector"
request-destination-name="testDestinationName"
request-channel="requestChannel"
selector="TestProperty = 'foo'"/>
<bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
<constructor-arg>
<bean class="org.springframework.integration.jms.StubConnection">
<constructor-arg value="test"/>
</bean>
</constructor-arg>
</bean>
</beans>

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:si="http://www.springframework.org/schema/integration"
xmlns:jms="http://www.springframework.org/schema/integration/jms"
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
http://www.springframework.org/schema/integration/jms
http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd">
<si:channel id="output1">
<si:queue capacity="1"/>
</si:channel>
<si:channel id="output2">
<si:queue capacity="1"/>
</si:channel>
<jms:inbound-channel-adapter id="pollingAdapter"
destination="testDestination"
selector="TestProperty = 'foo'"
channel="output1">
<si:poller max-messages-per-poll="1">
<si:interval-trigger interval="10000"/>
</si:poller>
</jms:inbound-channel-adapter>
<jms:message-driven-channel-adapter id="messageDrivenAdapter"
destination="testDestination"
selector="TestProperty = 'foo'"
channel="output2"/>
<bean id="testDestination" class="org.springframework.integration.jms.StubDestination"/>
<bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
<constructor-arg>
<bean class="org.springframework.integration.jms.StubConnection">
<constructor-arg value="test"/>
</bean>
</constructor-arg>
</bean>
</beans>