Skip to content

Commit 2c7d2d3

Browse files
committed
Support custom resolution of response destination
Previously, the "pubSubDomain" drove the resolution of both the destination of the listener and the default response destination. A new "replyPubSubDomain" attribute has been added on the base listener and can be used to listen on a topic and reply to a queue (or vice versa). The attribute is exposed via the "response-destination-type" XML attribute on the listener container element. It is also available on the JmsListenerContainerFactory for use with the @JmsListener infrastructure. Issue: SPR-12911
1 parent e403aef commit 2c7d2d3

File tree

16 files changed

+835
-16
lines changed

16 files changed

+835
-16
lines changed

spring-jms/src/main/java/org/springframework/jms/config/AbstractJmsListenerContainerFactory.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ public abstract class AbstractJmsListenerContainerFactory<C extends AbstractMess
5252

5353
private Boolean pubSubDomain;
5454

55+
private Boolean replyPubSubDomain;
56+
5557
private Boolean subscriptionDurable;
5658

5759
private Boolean subscriptionShared;
@@ -112,6 +114,13 @@ public void setPubSubDomain(Boolean pubSubDomain) {
112114
this.pubSubDomain = pubSubDomain;
113115
}
114116

117+
/**
118+
* @see AbstractMessageListenerContainer#setReplyPubSubDomain(boolean)
119+
*/
120+
public void setReplyPubSubDomain(Boolean replyPubSubDomain) {
121+
this.replyPubSubDomain = replyPubSubDomain;
122+
}
123+
115124
/**
116125
* @see AbstractMessageListenerContainer#setSubscriptionDurable(boolean)
117126
*/
@@ -172,6 +181,9 @@ public C createListenerContainer(JmsListenerEndpoint endpoint) {
172181
if (this.pubSubDomain != null) {
173182
instance.setPubSubDomain(this.pubSubDomain);
174183
}
184+
if (this.replyPubSubDomain != null) {
185+
instance.setReplyPubSubDomain(this.replyPubSubDomain);
186+
}
175187
if (this.subscriptionDurable != null) {
176188
instance.setSubscriptionDurable(this.subscriptionDurable);
177189
}

spring-jms/src/main/java/org/springframework/jms/config/AbstractListenerContainerParser.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -78,6 +78,8 @@ abstract class AbstractListenerContainerParser implements BeanDefinitionParser {
7878

7979
protected static final String DESTINATION_TYPE_SHARED_DURABLE_TOPIC = "sharedDurableTopic";
8080

81+
protected static final String RESPONSE_DESTINATION_TYPE_ATTRIBUTE = "response-destination-type";
82+
8183
protected static final String CLIENT_ID_ATTRIBUTE = "client-id";
8284

8385
protected static final String ACKNOWLEDGE_ATTRIBUTE = "acknowledge";
@@ -170,7 +172,7 @@ private void parseListener(Element containerEle, Element listenerEle, ParserCont
170172

171173
if (listenerEle.hasAttribute(RESPONSE_DESTINATION_ATTRIBUTE)) {
172174
String responseDestination = listenerEle.getAttribute(RESPONSE_DESTINATION_ATTRIBUTE);
173-
Boolean pubSubDomain = (Boolean) commonContainerProperties.getPropertyValue("pubSubDomain").getValue();
175+
Boolean pubSubDomain = (Boolean) commonContainerProperties.getPropertyValue("replyPubSubDomain").getValue();
174176
listenerDef.getPropertyValues().add(
175177
pubSubDomain ? "defaultResponseTopicName" : "defaultResponseQueueName", responseDestination);
176178
if (containerDef.getPropertyValues().contains("destinationResolver")) {
@@ -260,6 +262,23 @@ else if ("".equals(destinationType) || DESTINATION_TYPE_QUEUE.equals(destination
260262
properties.add("subscriptionDurable", subscriptionDurable);
261263
properties.add("subscriptionShared", subscriptionShared);
262264

265+
boolean replyPubSubDomain = false;
266+
String replyDestinationType = containerEle.getAttribute(RESPONSE_DESTINATION_TYPE_ATTRIBUTE);
267+
if (DESTINATION_TYPE_TOPIC.equals(replyDestinationType)) {
268+
replyPubSubDomain = true;
269+
}
270+
else if (DESTINATION_TYPE_QUEUE.equals(replyDestinationType)) {
271+
replyPubSubDomain = false;
272+
}
273+
else if (!StringUtils.hasText(replyDestinationType)) {
274+
replyPubSubDomain = pubSubDomain; // the default: same value as pubSubDomain
275+
}
276+
else if (StringUtils.hasText(replyDestinationType)) {
277+
parserContext.getReaderContext().error("Invalid listener container 'response-destination-type': only " +
278+
"\"queue\", \"topic\" supported.", containerEle);
279+
}
280+
properties.add("replyPubSubDomain", replyPubSubDomain);
281+
263282
if (containerEle.hasAttribute(CLIENT_ID_ATTRIBUTE)) {
264283
String clientId = containerEle.getAttribute(CLIENT_ID_ATTRIBUTE);
265284
if (!StringUtils.hasText(clientId)) {

spring-jms/src/main/java/org/springframework/jms/config/MethodJmsListenerEndpoint.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -89,7 +89,7 @@ protected MessagingMessageListenerAdapter createMessageListener(MessageListenerC
8989
messageListener.setHandlerMethod(invocableHandlerMethod);
9090
String responseDestination = getDefaultResponseDestination();
9191
if (StringUtils.hasText(responseDestination)) {
92-
if (container.isPubSubDomain()) {
92+
if (container.isReplyPubSubDomain()) {
9393
messageListener.setDefaultResponseTopicName(responseDestination);
9494
}
9595
else {

spring-jms/src/main/java/org/springframework/jms/listener/AbstractMessageListenerContainer.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ public abstract class AbstractMessageListenerContainer extends AbstractJmsListen
153153

154154
private String subscriptionName;
155155

156+
private Boolean replyPubSubDomain;
157+
156158
private boolean pubSubNoLocal = false;
157159

158160
private MessageConverter messageConverter;
@@ -445,6 +447,34 @@ public boolean isPubSubNoLocal() {
445447
return this.pubSubNoLocal;
446448
}
447449

450+
/**
451+
* Configure the reply destination type. By default, the configured {@code pubSubDomain}
452+
* value is used (see {@link #isPubSubDomain()}.
453+
* <p>This setting primarily indicates what type of destination to resolve
454+
* if dynamic destinations are enabled.
455+
* @param replyPubSubDomain "true" for the Publish/Subscribe domain ({@link javax.jms.Topic Topics}),
456+
* "false" for the Point-to-Point domain ({@link javax.jms.Queue Queues})
457+
* @see #setDestinationResolver
458+
*/
459+
public void setReplyPubSubDomain(boolean replyPubSubDomain) {
460+
this.replyPubSubDomain = replyPubSubDomain;
461+
}
462+
463+
/**
464+
* Return whether the Publish/Subscribe domain ({@link javax.jms.Topic Topics}) is used
465+
* for replies. Otherwise, the Point-to-Point domain ({@link javax.jms.Queue Queues}) is
466+
* used.
467+
*/
468+
@Override
469+
public boolean isReplyPubSubDomain() {
470+
if (this.replyPubSubDomain != null) {
471+
return replyPubSubDomain;
472+
}
473+
else {
474+
return isPubSubDomain();
475+
}
476+
}
477+
448478
/**
449479
* Set the {@link MessageConverter} strategy for converting JMS Messages.
450480
* @since 4.1

spring-jms/src/main/java/org/springframework/jms/listener/MessageListenerContainer.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -47,4 +47,12 @@ public interface MessageListenerContainer extends SmartLifecycle {
4747
*/
4848
boolean isPubSubDomain();
4949

50+
/**
51+
* Return whether the reply destination uses Publish/Subscribe domain
52+
* ({@link javax.jms.Topic Topics}). Otherwise, the Point-to-Point domain
53+
* ({@link javax.jms.Queue Queues}) is used.
54+
* <p>By default, the value is identical to {@link #isPubSubDomain()}.
55+
*/
56+
boolean isReplyPubSubDomain();
57+
5058
}

spring-jms/src/main/java/org/springframework/jms/listener/endpoint/JmsActivationSpecConfig.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -46,6 +46,8 @@ public class JmsActivationSpecConfig {
4646

4747
private boolean pubSubDomain = false;
4848

49+
private Boolean replyPubSubDomain;
50+
4951
private boolean subscriptionDurable = false;
5052

5153
private boolean subscriptionShared = false;
@@ -81,6 +83,19 @@ public boolean isPubSubDomain() {
8183
return this.pubSubDomain;
8284
}
8385

86+
public void setReplyPubSubDomain(boolean replyPubSubDomain) {
87+
this.replyPubSubDomain = replyPubSubDomain;
88+
}
89+
90+
public boolean isReplyPubSubDomain() {
91+
if (this.replyPubSubDomain != null) {
92+
return this.replyPubSubDomain;
93+
}
94+
else {
95+
return isPubSubDomain();
96+
}
97+
}
98+
8499
public void setSubscriptionDurable(boolean subscriptionDurable) {
85100
this.subscriptionDurable = subscriptionDurable;
86101
if (subscriptionDurable) {

spring-jms/src/main/java/org/springframework/jms/listener/endpoint/JmsMessageEndpointManager.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -200,4 +200,13 @@ public boolean isPubSubDomain() {
200200
throw new IllegalStateException("Could not determine pubSubDomain - no activation spec config is set");
201201
}
202202

203+
@Override
204+
public boolean isReplyPubSubDomain() {
205+
JmsActivationSpecConfig config = getActivationSpecConfig();
206+
if (config != null) {
207+
return config.isReplyPubSubDomain();
208+
}
209+
throw new IllegalStateException("Could not determine reply pubSubDomain - no activation spec config is set");
210+
}
211+
203212
}

spring-jms/src/main/resources/META-INF/spring.schemas

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ http\://www.springframework.org/schema/jms/spring-jms-3.1.xsd=org/springframewor
44
http\://www.springframework.org/schema/jms/spring-jms-3.2.xsd=org/springframework/jms/config/spring-jms-3.2.xsd
55
http\://www.springframework.org/schema/jms/spring-jms-4.0.xsd=org/springframework/jms/config/spring-jms-4.0.xsd
66
http\://www.springframework.org/schema/jms/spring-jms-4.1.xsd=org/springframework/jms/config/spring-jms-4.1.xsd
7-
http\://www.springframework.org/schema/jms/spring-jms.xsd=org/springframework/jms/config/spring-jms-4.1.xsd
7+
http\://www.springframework.org/schema/jms/spring-jms-4.2.xsd=org/springframework/jms/config/spring-jms-4.2.xsd
8+
http\://www.springframework.org/schema/jms/spring-jms.xsd=org/springframework/jms/config/spring-jms-4.2.xsd

0 commit comments

Comments
 (0)