diff --git a/spring-integration-http/src/main/java/org/springframework/integration/http/config/HttpInboundEndpointParser.java b/spring-integration-http/src/main/java/org/springframework/integration/http/config/HttpInboundEndpointParser.java
index d60a447358..ef8685dd4d 100644
--- a/spring-integration-http/src/main/java/org/springframework/integration/http/config/HttpInboundEndpointParser.java
+++ b/spring-integration-http/src/main/java/org/springframework/integration/http/config/HttpInboundEndpointParser.java
@@ -17,6 +17,7 @@
package org.springframework.integration.http.config;
import java.util.List;
+
import org.w3c.dom.Element;
import org.springframework.beans.factory.BeanDefinitionStoreException;
@@ -74,7 +75,7 @@ public class HttpInboundEndpointParser extends AbstractSingleBeanDefinitionParse
throws BeanDefinitionStoreException {
String id = super.resolveId(element, definition, parserContext);
- if (!element.hasAttribute(getInputChannelAttributeName())) {
+ if (!this.expectReply && !element.hasAttribute("channel")) {
// the created channel will get the 'id', so the adapter's bean name includes a suffix
id = id + ".adapter";
}
diff --git a/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsMessageDrivenEndpointParser.java b/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsMessageDrivenEndpointParser.java
index 3276096978..54abca2327 100644
--- a/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsMessageDrivenEndpointParser.java
+++ b/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsMessageDrivenEndpointParser.java
@@ -18,14 +18,17 @@ package org.springframework.integration.jms.config;
import org.w3c.dom.Element;
+import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
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.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.jms.JmsMessageDrivenEndpoint;
+import org.springframework.jms.listener.DefaultMessageListenerContainer;
import org.springframework.util.StringUtils;
/**
@@ -79,6 +82,22 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
return JmsMessageDrivenEndpoint.class.getName();
}
+ @Override
+ protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
+ throws BeanDefinitionStoreException {
+ String id = super.resolveId(element, definition, parserContext);
+
+ if (!this.expectReply && !element.hasAttribute("channel")) {
+ // the created channel will get the 'id', so the adapter's bean name includes a suffix
+ id = id + ".adapter";
+ }
+ if (!StringUtils.hasText(id)) {
+ id = BeanDefinitionReaderUtils.generateBeanName(definition, parserContext.getRegistry());
+ }
+
+ return id;
+ }
+
@Override
protected boolean shouldGenerateId() {
return false;
@@ -100,7 +119,11 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
}
private String parseMessageListenerContainer(Element element, ParserContext parserContext) {
+ String containerClass = element.getAttribute("container-class");
if (element.hasAttribute("container")) {
+ if (StringUtils.hasText(containerClass)) {
+ parserContext.getReaderContext().error("Cannot have both 'container' and 'container-class'", element);
+ }
for (String containerAttribute : containerAttributes) {
if (element.hasAttribute(containerAttribute)) {
parserContext.getReaderContext().error("The '" + containerAttribute +
@@ -110,8 +133,13 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
return element.getAttribute("container");
}
// otherwise, we build a DefaultMessageListenerContainer instance
- BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
- "org.springframework.jms.listener.DefaultMessageListenerContainer");
+ BeanDefinitionBuilder builder;
+ if (StringUtils.hasText(containerClass)) {
+ builder = BeanDefinitionBuilder.genericBeanDefinition(containerClass);
+ }
+ else {
+ builder = BeanDefinitionBuilder.genericBeanDefinition(DefaultMessageListenerContainer.class);
+ }
String destinationAttribute = this.expectReply ? "request-destination" : "destination";
String destinationNameAttribute = this.expectReply ? "request-destination-name" : "destination-name";
String pubSubDomainAttribute = this.expectReply ? "request-pub-sub-domain" : "pub-sub-domain";
@@ -198,7 +226,11 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel");
}
else {
- IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "channel", "requestChannel");
+ String channelName = element.getAttribute("channel");
+ if (!StringUtils.hasText(channelName)) {
+ channelName = IntegrationNamespaceUtils.createDirectChannel(element, parserContext);
+ }
+ builder.addPropertyReference("requestChannel", channelName);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "send-timeout", "requestTimeout");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "extract-payload", "extractRequestPayload");
}
diff --git a/spring-integration-jms/src/main/resources/org/springframework/integration/jms/config/spring-integration-jms-3.0.xsd b/spring-integration-jms/src/main/resources/org/springframework/integration/jms/config/spring-integration-jms-3.0.xsd
index a3aedd4afa..6e967bed3a 100644
--- a/spring-integration-jms/src/main/resources/org/springframework/integration/jms/config/spring-integration-jms-3.0.xsd
+++ b/spring-integration-jms/src/main/resources/org/springframework/integration/jms/config/spring-integration-jms-3.0.xsd
@@ -1201,6 +1201,11 @@
+
@@ -1208,6 +1213,22 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsMessageDrivenChannelAdapterParserTests.java b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsMessageDrivenChannelAdapterParserTests.java
index 6c4d094a33..5f1475b3c6 100644
--- a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsMessageDrivenChannelAdapterParserTests.java
+++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsMessageDrivenChannelAdapterParserTests.java
@@ -27,6 +27,7 @@ import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
+import org.springframework.integration.MessageChannel;
import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.history.MessageHistory;
import org.springframework.integration.jms.JmsMessageDrivenEndpoint;
@@ -38,6 +39,7 @@ import org.springframework.jms.support.destination.JmsDestinationAccessor;
/**
* @author Mark Fisher
* @author Michael Bannister
+ * @author Gary Russell
*/
public class JmsMessageDrivenChannelAdapterParserTests {
@@ -87,7 +89,7 @@ public class JmsMessageDrivenChannelAdapterParserTests {
public void adapterWithTaskExecutor() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsInboundWithTaskExecutor.xml", this.getClass());
- JmsMessageDrivenEndpoint endpoint = context.getBean("messageDrivenAdapter", JmsMessageDrivenEndpoint.class);
+ JmsMessageDrivenEndpoint endpoint = context.getBean("messageDrivenAdapter.adapter", JmsMessageDrivenEndpoint.class);
DefaultMessageListenerContainer container = TestUtils.getPropertyValue(endpoint, "listenerContainer",
DefaultMessageListenerContainer.class);
assertSame(context.getBean("exec"), TestUtils.getPropertyValue(container, "taskExecutor"));
@@ -95,52 +97,70 @@ public class JmsMessageDrivenChannelAdapterParserTests {
}
@Test
- public void testGatewayWithReceiveTimeout() {
+ public void testAdapterWithReceiveTimeout() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsInboundWithContainerSettings.xml", this.getClass());
- JmsMessageDrivenEndpoint gateway = (JmsMessageDrivenEndpoint) context.getBean("adapterWithReceiveTimeout");
- gateway.start();
+ JmsMessageDrivenEndpoint adapter = (JmsMessageDrivenEndpoint) context.getBean("adapterWithReceiveTimeout.adapter");
+ adapter.start();
AbstractMessageListenerContainer container = (AbstractMessageListenerContainer)
- new DirectFieldAccessor(gateway).getPropertyValue("listenerContainer");
+ new DirectFieldAccessor(adapter).getPropertyValue("listenerContainer");
assertEquals(1111L, new DirectFieldAccessor(container).getPropertyValue("receiveTimeout"));
- gateway.stop();
+ adapter.stop();
}
@Test
- public void testGatewayWithRecoveryInterval() {
+ public void testAdapterWithRecoveryInterval() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsInboundWithContainerSettings.xml", this.getClass());
- JmsMessageDrivenEndpoint gateway = (JmsMessageDrivenEndpoint) context.getBean("adapterWithRecoveryInterval");
- gateway.start();
+ JmsMessageDrivenEndpoint adapter = (JmsMessageDrivenEndpoint) context.getBean("adapterWithRecoveryInterval.adapter");
+ adapter.start();
AbstractMessageListenerContainer container = (AbstractMessageListenerContainer)
- new DirectFieldAccessor(gateway).getPropertyValue("listenerContainer");
+ new DirectFieldAccessor(adapter).getPropertyValue("listenerContainer");
assertEquals(2222L, new DirectFieldAccessor(container).getPropertyValue("recoveryInterval"));
- gateway.stop();
+ adapter.stop();
}
@Test
- public void testGatewayWithIdleTaskExecutionLimit() {
+ public void testAdapterWithIdleTaskExecutionLimit() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsInboundWithContainerSettings.xml", this.getClass());
- JmsMessageDrivenEndpoint gateway = (JmsMessageDrivenEndpoint) context.getBean("adapterWithIdleTaskExecutionLimit");
- gateway.start();
+ JmsMessageDrivenEndpoint adapter = (JmsMessageDrivenEndpoint) context.getBean("adapterWithIdleTaskExecutionLimit.adapter");
+ adapter.start();
AbstractMessageListenerContainer container = (AbstractMessageListenerContainer)
- new DirectFieldAccessor(gateway).getPropertyValue("listenerContainer");
+ new DirectFieldAccessor(adapter).getPropertyValue("listenerContainer");
assertEquals(7, new DirectFieldAccessor(container).getPropertyValue("idleTaskExecutionLimit"));
- gateway.stop();
+ adapter.stop();
}
@Test
- public void testGatewayWithIdleConsumerLimit() {
+ public void testAdapterWithIdleConsumerLimit() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsInboundWithContainerSettings.xml", this.getClass());
- JmsMessageDrivenEndpoint gateway = (JmsMessageDrivenEndpoint) context.getBean("adapterWithIdleConsumerLimit");
- gateway.start();
+ JmsMessageDrivenEndpoint adapter = (JmsMessageDrivenEndpoint) context.getBean("adapterWithIdleConsumerLimit.adapter");
+ adapter.start();
AbstractMessageListenerContainer container = (AbstractMessageListenerContainer)
- new DirectFieldAccessor(gateway).getPropertyValue("listenerContainer");
+ new DirectFieldAccessor(adapter).getPropertyValue("listenerContainer");
assertEquals(33, new DirectFieldAccessor(container).getPropertyValue("idleConsumerLimit"));
assertEquals(3, new DirectFieldAccessor(container).getPropertyValue("cacheLevel"));
- gateway.stop();
+ adapter.stop();
+ }
+
+ @Test
+ public void testAdapterWithContainerClass() {
+ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
+ "jmsInboundWithContainerClass.xml", this.getClass());
+ JmsMessageDrivenEndpoint adapter = context.getBean("adapterWithIdleConsumerLimit.adapter", JmsMessageDrivenEndpoint.class);
+ MessageChannel channel = context.getBean("adapterWithIdleConsumerLimit", MessageChannel.class);
+ assertSame(channel, TestUtils.getPropertyValue(adapter, "listener.gatewayDelegate.requestChannel"));
+ adapter.start();
+ FooContainer container = TestUtils.getPropertyValue(adapter, "listenerContainer", FooContainer.class);
+ assertEquals(33, new DirectFieldAccessor(container).getPropertyValue("idleConsumerLimit"));
+ assertEquals(3, new DirectFieldAccessor(container).getPropertyValue("cacheLevel"));
+ adapter.stop();
+ }
+
+ public static final class FooContainer extends DefaultMessageListenerContainer {
+
}
}
diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsInboundWithContainerClass.xml b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsInboundWithContainerClass.xml
new file mode 100644
index 0000000000..34bba45821
--- /dev/null
+++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsInboundWithContainerClass.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/reference/docbook/jms.xml b/src/reference/docbook/jms.xml
index 9e482ffe38..f8b8c5169d 100644
--- a/src/reference/docbook/jms.xml
+++ b/src/reference/docbook/jms.xml
@@ -87,12 +87,21 @@
message-driven Channel Adapter with a Destination reference.
]]>
+
The Message-Driven adapter also accepts several properties that pertain to the MessageListener container.
- These values are only considered if you do not provide an actual 'container' reference. In that case,
+ These values are only considered if you do not provide a container reference. In that case,
an instance of DefaultMessageListenerContainer will be created and configured based on these properties.
For example, you can specify the "transaction-manager" reference, the "concurrent-consumers" value, and
several other property references and values. Refer to the JavaDoc and Spring Integration's JMS Schema
- (spring-integration-jms.xsd) for more detail.
+ (spring-integration-jms.xsd) for more details.
+
+
+ If you have a custom listener container implementation (usually a subclass of
+ DefaultMessageListenerContainer), you can either provide a reference to an instance
+ of it using the container attribute, or simply provide its fully qualified class name using
+ the container-class attribute. In that case, the attributes on the adapter
+ are transferred to an instance of your custom container.
+