Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
INT-3677: Support PPH and SpEL for Container Class
JIRA: https://jira.spring.io/browse/INT-3677

Previously, you could not use a property placeholder or SpEL when
defining the `container-class` attribute on message-driven endpoints.

Register the container with bean name `adapterId.container`.

Also add an alias for the container message listener `adapterId.listener`.

Add tests for JMS-backed channels - no code changes needed because a factory bean is used.
  • Loading branch information
garyrussell authored and artembilan committed May 12, 2015
1 parent 123b38a commit 093ab79
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 19 deletions.
Expand Up @@ -27,6 +27,7 @@
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.ChannelPublishingJmsMessageListener;
import org.springframework.integration.jms.JmsMessageDrivenEndpoint;
import org.springframework.jms.listener.DefaultMessageListenerContainer;
import org.springframework.util.StringUtils;
Expand Down Expand Up @@ -111,8 +112,8 @@ protected boolean shouldGenerateIdAsFallback() {

@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
String containerBeanName = this.parseMessageListenerContainer(element, parserContext);
String listenerBeanName = this.parseMessageListener(element, parserContext);
String containerBeanName = this.parseMessageListenerContainer(element, parserContext, builder.getRawBeanDefinition());
String listenerBeanName = this.parseMessageListener(element, parserContext, builder.getRawBeanDefinition());
builder.addConstructorArgReference(containerBeanName);
builder.addConstructorArgReference(listenerBeanName);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, IntegrationNamespaceUtils.AUTO_STARTUP);
Expand All @@ -121,7 +122,8 @@ protected void doParse(Element element, ParserContext parserContext, BeanDefinit

}

private String parseMessageListenerContainer(Element element, ParserContext parserContext) {
private String parseMessageListenerContainer(Element element, ParserContext parserContext,
BeanDefinition adapterBeanDefinition) {
String containerClass = element.getAttribute("container-class");
if (element.hasAttribute("container")) {
if (StringUtils.hasText(containerClass)) {
Expand Down Expand Up @@ -182,12 +184,16 @@ private String parseMessageListenerContainer(Element element, ParserContext pars
"subscriptionName");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "client-id");
builder.addPropertyValue("autoStartup", false);
return BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry());
String beanName = adapterBeanNameRoot(element, parserContext, adapterBeanDefinition)
+ ".container";
parserContext.getRegistry().registerBeanDefinition(beanName, builder.getBeanDefinition());
return beanName;
}

private String parseMessageListener(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
"org.springframework.integration.jms.ChannelPublishingJmsMessageListener");
private String parseMessageListener(Element element, ParserContext parserContext,
BeanDefinition adapterBeanDefinition) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(ChannelPublishingJmsMessageListener.class);
builder.addPropertyValue("expectReply", this.expectReply);
if (this.expectReply) {
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "request-channel");
Expand Down Expand Up @@ -233,11 +239,22 @@ private String parseMessageListener(Element element, ParserContext parserContext
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "error-channel");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "message-converter");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "header-mapper");
String alias = adapterBeanNameRoot(element, parserContext, adapterBeanDefinition)
+ ".listener";
BeanDefinition beanDefinition = builder.getBeanDefinition();
String beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, parserContext.getRegistry());
BeanComponentDefinition component = new BeanComponentDefinition(beanDefinition, beanName);
BeanComponentDefinition component = new BeanComponentDefinition(beanDefinition, beanName, new String[] { alias });
parserContext.registerBeanComponent(component);
return beanName;
}

private String adapterBeanNameRoot(Element element, ParserContext parserContext,
BeanDefinition adapterBeanDefinition) {
String beanName = element.getAttribute(ID_ATTRIBUTE);
if (!StringUtils.hasText(beanName)) {
beanName = BeanDefinitionReaderUtils.generateBeanName(adapterBeanDefinition, parserContext.getRegistry());
}
return beanName;
}

}
Expand Up @@ -79,6 +79,9 @@
container-type="simple"/>

<jms:channel id="withContainerClass" queue-name="custom.container.queue"
container-class="org.springframework.integration.jms.config.JmsChannelParserTests$CustomTestMessageListenerContainer" />
container-class="${container.class}" />

<jms:channel id="withContainerClassSpEL" queue-name="custom.container.queue"
container-class="#{'org.springframework.integration.jms.config.JmsChannelParserTests$CustomTestMessageListenerContainer'}" />

</beans>
Expand Up @@ -17,8 +17,6 @@
package org.springframework.integration.jms.config;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;

import java.util.List;
Expand Down Expand Up @@ -117,6 +115,9 @@ public class JmsChannelParserTests {
@Autowired
private MessageChannel withContainerClass;

@Autowired
private MessageChannel withContainerClassSpEL;

@Autowired
private MessageBuilderFactory messageBuilderFactory;

Expand Down Expand Up @@ -300,6 +301,14 @@ public void withContainerClass() {
assertEquals("custom.container.queue", container.getDestinationName());
}

@Test
public void withContainerClassSpEL() {
CustomTestMessageListenerContainer container = TestUtils.getPropertyValue(
withContainerClassSpEL, "container",
CustomTestMessageListenerContainer.class);
assertEquals("custom.container.queue", container.getDestinationName());
}


static class TestDestinationResolver implements DestinationResolver {

Expand Down
Expand Up @@ -173,6 +173,29 @@ public void testAdapterWithContainerClass() {
assertSame(channel, TestUtils.getPropertyValue(adapter, "listener.gatewayDelegate.requestChannel"));
adapter.start();
FooContainer container = TestUtils.getPropertyValue(adapter, "listenerContainer", FooContainer.class);
assertSame(container, context.getBean("adapterWithIdleConsumerLimit.container"));
assertEquals(33, new DirectFieldAccessor(container).getPropertyValue("idleConsumerLimit"));
assertEquals(3, new DirectFieldAccessor(container).getPropertyValue("cacheLevel"));
assertSame(context.getBean("adapterWithIdleConsumerLimit.listener"),
TestUtils.getPropertyValue(container, "messageListener"));
adapter.stop();

adapter = context.getBean("adapterWithIdleConsumerLimit2.adapter", JmsMessageDrivenEndpoint.class);
channel = context.getBean("adapterWithIdleConsumerLimit2", MessageChannel.class);
assertSame(channel, TestUtils.getPropertyValue(adapter, "listener.gatewayDelegate.requestChannel"));
adapter.start();
container = TestUtils.getPropertyValue(adapter, "listenerContainer", FooContainer.class);
assertSame(container, context.getBean("adapterWithIdleConsumerLimit2.container"));
assertEquals(33, new DirectFieldAccessor(container).getPropertyValue("idleConsumerLimit"));
assertEquals(3, new DirectFieldAccessor(container).getPropertyValue("cacheLevel"));
adapter.stop();

adapter = context.getBean("org.springframework.integration.jms.JmsMessageDrivenEndpoint#0", JmsMessageDrivenEndpoint.class);
channel = context.getBean("in", MessageChannel.class);
assertSame(channel, TestUtils.getPropertyValue(adapter, "listener.gatewayDelegate.requestChannel"));
adapter.start();
container = TestUtils.getPropertyValue(adapter, "listenerContainer", FooContainer.class);
assertSame(container, context.getBean("org.springframework.integration.jms.JmsMessageDrivenEndpoint#0.container"));
assertEquals(33, new DirectFieldAccessor(container).getPropertyValue("idleConsumerLimit"));
assertEquals(3, new DirectFieldAccessor(container).getPropertyValue("cacheLevel"));
adapter.stop();
Expand Down
@@ -1,2 +1,3 @@
queue=testQueue
concurrency=5-25
concurrency=5-25
container.class=org.springframework.integration.jms.config.JmsChannelParserTests$CustomTestMessageListenerContainer
Expand Up @@ -3,21 +3,47 @@
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">
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/integration/jms http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

<util:properties id="props">
<prop key="container.class">org.springframework.integration.jms.config.JmsMessageDrivenChannelAdapterParserTests$FooContainer</prop>
</util:properties>

<context:property-placeholder properties-ref="props"/>

<jms:message-driven-channel-adapter id="adapterWithIdleConsumerLimit"
connection-factory="testConnectionFactory"
destination-name="testQueue"
container-class="org.springframework.integration.jms.config.JmsMessageDrivenChannelAdapterParserTests$FooContainer"
container-class="${container.class}"
idle-consumer-limit="33"
cache-level="3"
auto-startup="false" />

<jms:message-driven-channel-adapter id="adapterWithIdleConsumerLimit2"
connection-factory="testConnectionFactory"
destination-name="testQueue"
container-class="#{props['container.class']}"
idle-consumer-limit="33"
cache-level="3"
auto-startup="false" />

<!-- no id -->
<jms:message-driven-channel-adapter channel="in"
connection-factory="testConnectionFactory"
destination-name="testQueue"
container-class="#{props['container.class']}"
idle-consumer-limit="33"
cache-level="3"
auto-startup="false" />

<si:channel id="in" />

<bean id="testConnectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
<constructor-arg>
<bean class="org.springframework.integration.jms.StubConnection">
Expand Down

0 comments on commit 093ab79

Please sign in to comment.