Merge pull request #49 from markfisher/INT-1109
add request-destination-expression for outbound-gateway add destination-expression for outbound-channel-adapter
This commit is contained in:
@@ -33,11 +33,14 @@ import javax.jms.TemporaryQueue;
|
||||
import javax.jms.TemporaryTopic;
|
||||
import javax.jms.Topic;
|
||||
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageChannel;
|
||||
import org.springframework.integration.MessageDeliveryException;
|
||||
import org.springframework.integration.MessageHandlingException;
|
||||
import org.springframework.integration.MessageTimeoutException;
|
||||
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
|
||||
import org.springframework.integration.handler.ExpressionEvaluatingMessageProcessor;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.jms.connection.ConnectionFactoryUtils;
|
||||
import org.springframework.jms.support.JmsUtils;
|
||||
@@ -61,6 +64,8 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler {
|
||||
|
||||
private volatile String requestDestinationName;
|
||||
|
||||
private volatile ExpressionEvaluatingMessageProcessor<?> requestDestinationExpressionProcessor;
|
||||
|
||||
private volatile Destination replyDestination;
|
||||
|
||||
private volatile String replyDestinationName;
|
||||
@@ -121,7 +126,7 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler {
|
||||
|
||||
/**
|
||||
* Set the JMS Destination to which request Messages should be sent.
|
||||
* Either this or the 'requestDestinationName' property is required.
|
||||
* Either this or one of 'requestDestinationName' or 'requestDestinationExpression' is required.
|
||||
*/
|
||||
public void setRequestDestination(Destination requestDestination) {
|
||||
if (requestDestination instanceof Topic) {
|
||||
@@ -131,13 +136,22 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the JMS Destination to which request Messages should be
|
||||
* sent. Either this or the 'requestDestination' property is required.
|
||||
* Set the name of the JMS Destination to which request Messages should be sent.
|
||||
* Either this or one of 'requestDestination' or 'requestDestinationExpression' is required.
|
||||
*/
|
||||
public void setRequestDestinationName(String requestDestinationName) {
|
||||
this.requestDestinationName = requestDestinationName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the SpEL Expression to be used for determining the request Destination instance
|
||||
* or request destination name. Either this or one of 'requestDestination' or
|
||||
* 'requestDestinationName' is required.
|
||||
*/
|
||||
public void setRequestDestinationExpression(Expression requestDestinationExpression) {
|
||||
this.requestDestinationExpressionProcessor = new ExpressionEvaluatingMessageProcessor<Object>(requestDestinationExpression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JMS Destination from which reply Messages should be received.
|
||||
* If none is provided, this gateway will create a {@link TemporaryQueue} per invocation.
|
||||
@@ -304,14 +318,33 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler {
|
||||
return "jms:outbound-gateway";
|
||||
}
|
||||
|
||||
private Destination getRequestDestination(Session session) throws JMSException {
|
||||
private Destination getRequestDestination(Message<?> message, Session session) throws JMSException {
|
||||
if (this.requestDestination != null) {
|
||||
return this.requestDestination;
|
||||
}
|
||||
if (this.requestDestinationName != null) {
|
||||
return this.resolveRequestDestination(this.requestDestinationName, session);
|
||||
}
|
||||
if (this.requestDestinationExpressionProcessor != null) {
|
||||
Object result = this.requestDestinationExpressionProcessor.processMessage(message);
|
||||
if (result instanceof Destination) {
|
||||
return (Destination) result;
|
||||
}
|
||||
if (result instanceof String) {
|
||||
return this.resolveRequestDestination((String) result, session);
|
||||
}
|
||||
throw new MessageDeliveryException(message,
|
||||
"Evaluation of requestDestinationExpression failed to produce a Destination or destination name. Result was: " + result);
|
||||
}
|
||||
throw new MessageDeliveryException(message,
|
||||
"No requestDestination, requestDestinationName, or requestDestinationExpression has been configured.");
|
||||
}
|
||||
|
||||
private Destination resolveRequestDestination(String requestDestinationName, Session session) throws JMSException {
|
||||
Assert.notNull(this.destinationResolver,
|
||||
"DestinationResolver is required when relying upon the 'requestDestinationName' property.");
|
||||
return this.destinationResolver.resolveDestinationName(
|
||||
session, this.requestDestinationName, this.requestPubSubDomain);
|
||||
session, requestDestinationName, this.requestPubSubDomain);
|
||||
}
|
||||
|
||||
private Destination getReplyDestination(Session session) throws JMSException {
|
||||
@@ -334,8 +367,14 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler {
|
||||
return;
|
||||
}
|
||||
Assert.notNull(this.connectionFactory, "connectionFactory must not be null");
|
||||
Assert.isTrue(this.requestDestination != null || this.requestDestinationName != null,
|
||||
"Either a 'requestDestination' or 'requestDestinationName' is required.");
|
||||
Assert.isTrue(this.requestDestination != null
|
||||
^ this.requestDestinationName != null
|
||||
^ this.requestDestinationExpressionProcessor != null,
|
||||
"Exactly one of 'requestDestination', 'requestDestinationName', or 'requestDestinationExpression' is required.");
|
||||
if (this.requestDestinationExpressionProcessor != null) {
|
||||
this.requestDestinationExpressionProcessor.setBeanFactory(getBeanFactory());
|
||||
this.requestDestinationExpressionProcessor.setConversionService(getConversionService());
|
||||
}
|
||||
this.initialized = true;
|
||||
}
|
||||
}
|
||||
@@ -402,14 +441,15 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler {
|
||||
priority = this.priority;
|
||||
}
|
||||
javax.jms.Message replyMessage = null;
|
||||
Destination requestDestination = this.getRequestDestination(requestMessage, session);
|
||||
if (this.correlationKey != null) {
|
||||
replyMessage = this.doSendAndReceiveWithGeneratedCorrelationId(jmsRequest, replyTo, session, priority);
|
||||
replyMessage = this.doSendAndReceiveWithGeneratedCorrelationId(requestDestination, jmsRequest, replyTo, session, priority);
|
||||
}
|
||||
else if (replyTo instanceof TemporaryQueue || replyTo instanceof TemporaryTopic) {
|
||||
replyMessage = this.doSendAndReceiveWithTemporaryReplyToDestination(jmsRequest, replyTo, session, priority);
|
||||
replyMessage = this.doSendAndReceiveWithTemporaryReplyToDestination(requestDestination, jmsRequest, replyTo, session, priority);
|
||||
}
|
||||
else {
|
||||
replyMessage = this.doSendAndReceiveWithMessageIdCorrelation(jmsRequest, replyTo, session, priority);
|
||||
replyMessage = this.doSendAndReceiveWithMessageIdCorrelation(requestDestination, jmsRequest, replyTo, session, priority);
|
||||
}
|
||||
return replyMessage;
|
||||
}
|
||||
@@ -423,11 +463,12 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler {
|
||||
/**
|
||||
* Creates the MessageConsumer before sending the request Message since we are generating our own correlationId value for the MessageSelector.
|
||||
*/
|
||||
private javax.jms.Message doSendAndReceiveWithGeneratedCorrelationId(javax.jms.Message jmsRequest, Destination replyTo, Session session, int priority) throws JMSException {
|
||||
private javax.jms.Message doSendAndReceiveWithGeneratedCorrelationId(Destination requestDestination,
|
||||
javax.jms.Message jmsRequest, Destination replyTo, Session session, int priority) throws JMSException {
|
||||
MessageProducer messageProducer = null;
|
||||
MessageConsumer messageConsumer = null;
|
||||
try {
|
||||
messageProducer = session.createProducer(this.getRequestDestination(session));
|
||||
messageProducer = session.createProducer(requestDestination);
|
||||
String correlationId = UUID.randomUUID().toString().replaceAll("'", "''");
|
||||
Assert.state(this.correlationKey != null, "correlationKey must not be null");
|
||||
String messageSelector = null;
|
||||
@@ -452,11 +493,12 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler {
|
||||
/**
|
||||
* Creates the MessageConsumer before sending the request Message since we do not need any correlation.
|
||||
*/
|
||||
private javax.jms.Message doSendAndReceiveWithTemporaryReplyToDestination(javax.jms.Message jmsRequest, Destination replyTo, Session session, int priority) throws JMSException {
|
||||
private javax.jms.Message doSendAndReceiveWithTemporaryReplyToDestination(Destination requestDestination,
|
||||
javax.jms.Message jmsRequest, Destination replyTo, Session session, int priority) throws JMSException {
|
||||
MessageProducer messageProducer = null;
|
||||
MessageConsumer messageConsumer = null;
|
||||
try {
|
||||
messageProducer = session.createProducer(this.getRequestDestination(session));
|
||||
messageProducer = session.createProducer(requestDestination);
|
||||
messageConsumer = session.createConsumer(replyTo);
|
||||
this.sendRequestMessage(jmsRequest, messageProducer, priority);
|
||||
return this.receiveReplyMessage(messageConsumer);
|
||||
@@ -470,7 +512,8 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler {
|
||||
/**
|
||||
* Creates the MessageConsumer after sending the request Message since we need the MessageID for correlation with a MessageSelector.
|
||||
*/
|
||||
private javax.jms.Message doSendAndReceiveWithMessageIdCorrelation(javax.jms.Message jmsRequest, Destination replyTo, Session session, int priority) throws JMSException {
|
||||
private javax.jms.Message doSendAndReceiveWithMessageIdCorrelation(Destination requestDestination,
|
||||
javax.jms.Message jmsRequest, Destination replyTo, Session session, int priority) throws JMSException {
|
||||
if (replyTo instanceof Topic && logger.isWarnEnabled()) {
|
||||
logger.warn("Relying on the MessageID for correlation is not recommended when using a Topic as the replyTo Destination " +
|
||||
"because that ID can only be provided to a MessageSelector after the reuqest Message has been sent thereby " +
|
||||
@@ -481,7 +524,7 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler {
|
||||
MessageProducer messageProducer = null;
|
||||
MessageConsumer messageConsumer = null;
|
||||
try {
|
||||
messageProducer = session.createProducer(this.getRequestDestination(session));
|
||||
messageProducer = session.createProducer(requestDestination);
|
||||
this.sendRequestMessage(jmsRequest, messageProducer, priority);
|
||||
String messageId = jmsRequest.getJMSMessageID().replaceAll("'", "''");
|
||||
String messageSelector = "JMSCorrelationID = '" + messageId + "'";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 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.
|
||||
@@ -19,8 +19,11 @@ package org.springframework.integration.jms;
|
||||
import javax.jms.Destination;
|
||||
import javax.jms.JMSException;
|
||||
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageDeliveryException;
|
||||
import org.springframework.integration.handler.AbstractMessageHandler;
|
||||
import org.springframework.integration.handler.ExpressionEvaluatingMessageProcessor;
|
||||
import org.springframework.jms.core.JmsTemplate;
|
||||
import org.springframework.jms.core.MessagePostProcessor;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -43,21 +46,31 @@ public class JmsSendingMessageHandler extends AbstractMessageHandler {
|
||||
|
||||
private volatile boolean extractPayload = true;
|
||||
|
||||
private volatile ExpressionEvaluatingMessageProcessor<?> destinationExpressionProcessor;
|
||||
|
||||
|
||||
public JmsSendingMessageHandler(JmsTemplate jmsTemplate) {
|
||||
this.jmsTemplate = jmsTemplate;
|
||||
}
|
||||
|
||||
public void setDestination(Destination destination) {
|
||||
Assert.isNull(this.destinationName, "The 'destination' and 'destinationName' properties are mutually exclusive.");
|
||||
Assert.isTrue(this.destinationName == null && this.destinationExpressionProcessor == null,
|
||||
"The 'destination', 'destinationName', and 'destinationExpression' properties are mutually exclusive.");
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public void setDestinationName(String destinationName) {
|
||||
Assert.isNull(this.destination, "The 'destination' and 'destinationName' properties are mutually exclusive.");
|
||||
Assert.isTrue(this.destination == null && this.destinationExpressionProcessor == null,
|
||||
"The 'destination', 'destinationName', and 'destinationExpression' properties are mutually exclusive.");
|
||||
this.destinationName = destinationName;
|
||||
}
|
||||
|
||||
public void setDestinationExpression(Expression destinationExpression) {
|
||||
Assert.isTrue(this.destination == null && this.destinationName == null,
|
||||
"The 'destination', 'destinationName', and 'destinationExpression' properties are mutually exclusive.");
|
||||
this.destinationExpressionProcessor = new ExpressionEvaluatingMessageProcessor<Object>(destinationExpression);
|
||||
}
|
||||
|
||||
public void setHeaderMapper(JmsHeaderMapper headerMapper) {
|
||||
this.headerMapper = headerMapper;
|
||||
}
|
||||
@@ -78,28 +91,55 @@ public class JmsSendingMessageHandler extends AbstractMessageHandler {
|
||||
return "jms:outbound-channel-adapter";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInit() {
|
||||
if (this.destinationExpressionProcessor != null) {
|
||||
this.destinationExpressionProcessor.setBeanFactory(getBeanFactory());
|
||||
this.destinationExpressionProcessor.setConversionService(getConversionService());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleMessageInternal(final Message<?> message) throws Exception {
|
||||
if (message == null) {
|
||||
throw new IllegalArgumentException("message must not be null");
|
||||
}
|
||||
Object destination = this.determineDestination(message);
|
||||
Object objectToSend = (this.extractPayload) ? message.getPayload() : message;
|
||||
MessagePostProcessor messagePostProcessor = new HeaderMappingMessagePostProcessor(message, this.headerMapper);
|
||||
try {
|
||||
DynamicJmsTemplateProperties.setPriority(message.getHeaders().getPriority());
|
||||
this.send(objectToSend, messagePostProcessor);
|
||||
this.send(destination, objectToSend, messagePostProcessor);
|
||||
}
|
||||
finally {
|
||||
DynamicJmsTemplateProperties.clearPriority();
|
||||
}
|
||||
}
|
||||
|
||||
private void send(Object objectToSend, MessagePostProcessor messagePostProcessor) {
|
||||
private Object determineDestination(Message<?> message) {
|
||||
if (this.destination != null) {
|
||||
this.jmsTemplate.convertAndSend(this.destination, objectToSend, messagePostProcessor);
|
||||
return this.destination;
|
||||
}
|
||||
else if (this.destinationName != null) {
|
||||
this.jmsTemplate.convertAndSend(this.destinationName, objectToSend, messagePostProcessor);
|
||||
if (this.destinationName != null) {
|
||||
return this.destinationName;
|
||||
}
|
||||
if (this.destinationExpressionProcessor != null) {
|
||||
Object result = this.destinationExpressionProcessor.processMessage(message);
|
||||
if (!(result instanceof Destination || result instanceof String)) {
|
||||
throw new MessageDeliveryException(message,
|
||||
"Evaluation of destinationExpression failed to produce a Destination or destination name. Result was: " + result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void send(Object destination, Object objectToSend, MessagePostProcessor messagePostProcessor) {
|
||||
if (destination instanceof Destination) {
|
||||
this.jmsTemplate.convertAndSend((Destination) destination, objectToSend, messagePostProcessor);
|
||||
}
|
||||
else if (destination instanceof String) {
|
||||
this.jmsTemplate.convertAndSend((String) destination, objectToSend, messagePostProcessor);
|
||||
}
|
||||
else { // fallback to default destination of the template
|
||||
this.jmsTemplate.convertAndSend(objectToSend, messagePostProcessor);
|
||||
@@ -124,5 +164,4 @@ public class JmsSendingMessageHandler extends AbstractMessageHandler {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -46,12 +46,16 @@ abstract class JmsAdapterParserUtils {
|
||||
|
||||
static final String DESTINATION_NAME_ATTRIBUTE = "destination-name";
|
||||
|
||||
static final String DESTINATION_NAME_PROPERTY = "destinationName";
|
||||
|
||||
static final String DESTINATION_EXPRESSION_ATTRIBUTE = "destination-expression";
|
||||
|
||||
static final String DESTINATION_EXPRESSION_PROPERTY = "destinationExpression";
|
||||
|
||||
static final String PUB_SUB_DOMAIN_ATTRIBUTE = "pub-sub-domain";
|
||||
|
||||
static final String PUB_SUB_DOMAIN_PROPERTY = "pubSubDomain";
|
||||
|
||||
static final String DESTINATION_NAME_PROPERTY = "destinationName";
|
||||
|
||||
static final String HEADER_MAPPER_ATTRIBUTE = "header-mapper";
|
||||
|
||||
static final String HEADER_MAPPER_PROPERTY = "headerMapper";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2011 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.
|
||||
@@ -21,6 +21,7 @@ import org.w3c.dom.Element;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.ExpressionFactoryBean;
|
||||
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -39,10 +40,12 @@ public class JmsOutboundChannelAdapterParser extends AbstractOutboundChannelAdap
|
||||
String jmsTemplate = element.getAttribute(JmsAdapterParserUtils.JMS_TEMPLATE_ATTRIBUTE);
|
||||
String destination = element.getAttribute(JmsAdapterParserUtils.DESTINATION_ATTRIBUTE);
|
||||
String destinationName = element.getAttribute(JmsAdapterParserUtils.DESTINATION_NAME_ATTRIBUTE);
|
||||
String destinationExpression = element.getAttribute(JmsAdapterParserUtils.DESTINATION_EXPRESSION_ATTRIBUTE);
|
||||
String headerMapper = element.getAttribute(JmsAdapterParserUtils.HEADER_MAPPER_ATTRIBUTE);
|
||||
boolean hasJmsTemplate = StringUtils.hasText(jmsTemplate);
|
||||
boolean hasDestinationRef = StringUtils.hasText(destination);
|
||||
boolean hasDestinationName = StringUtils.hasText(destinationName);
|
||||
boolean hasDestinationExpression = StringUtils.hasText(destinationExpression);
|
||||
if (hasJmsTemplate) {
|
||||
JmsAdapterParserUtils.verifyNoJmsTemplateAttributes(element, parserContext);
|
||||
builder.addConstructorArgReference(jmsTemplate);
|
||||
@@ -50,22 +53,29 @@ public class JmsOutboundChannelAdapterParser extends AbstractOutboundChannelAdap
|
||||
else {
|
||||
builder.addConstructorArgValue(JmsAdapterParserUtils.parseJmsTemplateBeanDefinition(element, parserContext));
|
||||
}
|
||||
if (hasDestinationRef || hasDestinationName) {
|
||||
|
||||
if (hasDestinationRef || hasDestinationName || hasDestinationExpression) {
|
||||
if (!(hasDestinationRef ^ hasDestinationName ^ hasDestinationExpression)) {
|
||||
parserContext.getReaderContext().error("The 'destination', 'destination-name', and " +
|
||||
"'destination-expression' attributes are mutually exclusive.", parserContext.extractSource(element));
|
||||
}
|
||||
if (hasDestinationRef) {
|
||||
if (hasDestinationName) {
|
||||
parserContext.getReaderContext().error("The 'destination-name' " +
|
||||
"and 'destination' attributes are mutually exclusive.", parserContext.extractSource(element));
|
||||
}
|
||||
builder.addPropertyReference(JmsAdapterParserUtils.DESTINATION_PROPERTY, destination);
|
||||
}
|
||||
else if (hasDestinationName) {
|
||||
builder.addPropertyValue(JmsAdapterParserUtils.DESTINATION_NAME_PROPERTY, destinationName);
|
||||
}
|
||||
else if (hasDestinationExpression) {
|
||||
BeanDefinitionBuilder expressionBuilder = BeanDefinitionBuilder.genericBeanDefinition(ExpressionFactoryBean.class);
|
||||
expressionBuilder.addConstructorArgValue(destinationExpression);
|
||||
builder.addPropertyValue(JmsAdapterParserUtils.DESTINATION_EXPRESSION_PROPERTY, expressionBuilder.getBeanDefinition());
|
||||
}
|
||||
}
|
||||
else if (!hasJmsTemplate) {
|
||||
parserContext.getReaderContext().error("either a '" + JmsAdapterParserUtils.JMS_TEMPLATE_ATTRIBUTE +
|
||||
"' or one of '" + JmsAdapterParserUtils.DESTINATION_ATTRIBUTE + "' or '"
|
||||
+ JmsAdapterParserUtils.DESTINATION_NAME_ATTRIBUTE +
|
||||
"' or one of '" + JmsAdapterParserUtils.DESTINATION_ATTRIBUTE + "', '"
|
||||
+ JmsAdapterParserUtils.DESTINATION_NAME_ATTRIBUTE + "', or '" +
|
||||
JmsAdapterParserUtils.DESTINATION_EXPRESSION_ATTRIBUTE +
|
||||
"' attributes must be provided", parserContext.extractSource(element));
|
||||
}
|
||||
if (StringUtils.hasText(headerMapper)) {
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.ExpressionFactoryBean;
|
||||
import org.springframework.integration.config.xml.AbstractConsumerEndpointParser;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -44,16 +45,25 @@ public class JmsOutboundGatewayParser extends AbstractConsumerEndpointParser {
|
||||
builder.addPropertyReference("connectionFactory", element.getAttribute("connection-factory"));
|
||||
String requestDestination = element.getAttribute("request-destination");
|
||||
String requestDestinationName = element.getAttribute("request-destination-name");
|
||||
if (!(StringUtils.hasText(requestDestination) ^ StringUtils.hasText(requestDestinationName))) {
|
||||
parserContext.getReaderContext().error(
|
||||
"Exactly one of the 'request-destination' or 'request-destination-name' attributes is required.", element);
|
||||
String requestDestinationExpression = element.getAttribute("request-destination-expression");
|
||||
boolean hasRequestDestination = StringUtils.hasText(requestDestination);
|
||||
boolean hasRequestDestinationName = StringUtils.hasText(requestDestinationName);
|
||||
boolean hasRequestDestinationExpression = StringUtils.hasText(requestDestinationExpression);
|
||||
if (!(hasRequestDestination ^ hasRequestDestinationName ^ hasRequestDestinationExpression)) {
|
||||
parserContext.getReaderContext().error("Exactly one of the 'request-destination', " +
|
||||
"'request-destination-name', or 'request-destination-expression' attributes is required.", element);
|
||||
}
|
||||
if (StringUtils.hasText(requestDestination)) {
|
||||
if (hasRequestDestination) {
|
||||
builder.addPropertyReference("requestDestination", requestDestination);
|
||||
}
|
||||
else if (StringUtils.hasText(requestDestinationName)) {
|
||||
else if (hasRequestDestinationName) {
|
||||
builder.addPropertyValue("requestDestinationName", requestDestinationName);
|
||||
}
|
||||
else if (hasRequestDestinationExpression) {
|
||||
BeanDefinitionBuilder expressionBuilder = BeanDefinitionBuilder.genericBeanDefinition(ExpressionFactoryBean.class);
|
||||
expressionBuilder.addConstructorArgValue(requestDestinationExpression);
|
||||
builder.addPropertyValue("requestDestinationExpression", expressionBuilder.getBeanDefinition());
|
||||
}
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-destination");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-destination-name");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel");
|
||||
|
||||
@@ -732,7 +732,9 @@
|
||||
<xsd:documentation>
|
||||
A reference to a javax.jms.Destination by bean name. As an alternative to a bean
|
||||
reference, use 'request-destination-name' and 'request-pub-sub-domain' which will rely
|
||||
upon the DestinationResolver strategy (DynamicDestinationResolver by default).
|
||||
upon the DestinationResolver strategy (DynamicDestinationResolver by default). This
|
||||
attribute is mutually exclusive with 'request-destination-name' and
|
||||
'request-destination-expression'.
|
||||
</xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
@@ -741,8 +743,34 @@
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="request-destination-name" type="xsd:string"/>
|
||||
<xsd:attribute name="request-pub-sub-domain" type="xsd:string"/>
|
||||
<xsd:attribute name="request-destination-name" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Name of a destination to which request messages will be sent. This name will be handled
|
||||
by this gateway's DestinationResolver. This attribute is mutually exclusive with
|
||||
'request-destination' and 'request-destination-expression'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="request-destination-expression" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
A SpEL expression to be evaluated at runtime against each Spring Integration request Message as
|
||||
the root object. The result should be either a Destination instance or a String representing
|
||||
the destination name. In the latter case, it will be passed to this adapter's DestinationResolver.
|
||||
This attribute is mutually exclusive with 'request-destination' and 'request-destination-name'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="request-pub-sub-domain" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
When resolving a request destination name (rather than having a 'request-destination' reference),
|
||||
a true value here specifies that the DestinationResolver should resolve Topics rather than Queues.
|
||||
Default is false.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="reply-destination" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
@@ -870,7 +898,8 @@
|
||||
<xsd:documentation>
|
||||
A reference to a javax.jms.Destination by bean name. As an alternative to a bean
|
||||
reference, use 'destination-name' and 'pub-sub-domain' which will rely upon the
|
||||
DestinationResolver strategy (DynamicDestinationResolver by default).
|
||||
DestinationResolver strategy (DynamicDestinationResolver by default). This attribute
|
||||
is mutually exclusive with 'destination-name' and 'destination-expression'.
|
||||
</xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
@@ -879,8 +908,33 @@
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="destination-name" type="xsd:string"/>
|
||||
<xsd:attribute name="pub-sub-domain" type="xsd:string"/>
|
||||
<xsd:attribute name="destination-name" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Name of the destination to which JMS Messages will be sent. This will be passed to the
|
||||
adapter's DestinationResolver. This attribute is mutually exclusive with 'destination'
|
||||
and 'destination-expression'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="destination-expression" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
A SpEL expression to be evaluated at runtime against each Spring Integration Message as
|
||||
the root object. The result should be either a Destination instance or a String representing
|
||||
the destination name. In the latter case, it will be passed to this adapter's DestinationResolver.
|
||||
If the evaluation result is null, messages will be sent to the default destination of the
|
||||
underlying JmsTemplate. This attribute is mutually exclusive with 'destination' and 'destination-name'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="pub-sub-domain" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
If true, specifies that destination names should resolve to Topics rather than Queues. Default is false.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="channel" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<?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:jms="http://www.springframework.org/schema/jms"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.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">
|
||||
|
||||
<int-jms:outbound-channel-adapter id="channelAdapterChannel" destination-expression="'queue.test.dynamic.adapter.' + headers.destinationNumber"/>
|
||||
|
||||
<int-jms:message-driven-channel-adapter channel="channelAdapterResults1" destination-name="queue.test.dynamic.adapter.1" extract-payload="false"/>
|
||||
|
||||
<int-jms:message-driven-channel-adapter channel="channelAdapterResults2" destination-name="queue.test.dynamic.adapter.2" extract-payload="false"/>
|
||||
|
||||
<int:channel id="gatewayChannel"/>
|
||||
|
||||
<int-jms:outbound-gateway request-channel="gatewayChannel" request-destination-expression="'queue.test.dynamic.gateway.' + headers.destinationNumber"/>
|
||||
|
||||
<int:channel id="channelAdapterResults1">
|
||||
<int:queue capacity="1"/>
|
||||
</int:channel>
|
||||
|
||||
<int:channel id="channelAdapterResults2">
|
||||
<int:queue capacity="1"/>
|
||||
</int:channel>
|
||||
|
||||
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
|
||||
<property name="targetConnectionFactory">
|
||||
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
|
||||
<property name="brokerURL" value="vm://localhost"/>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="sessionCacheSize" value="10"/>
|
||||
<property name="cacheProducers" value="false"/>
|
||||
</bean>
|
||||
|
||||
<jms:listener-container>
|
||||
<jms:listener destination="queue.test.dynamic.gateway.1" ref="responder" method="one"/>
|
||||
<jms:listener destination="queue.test.dynamic.gateway.2" ref="responder" method="two"/>
|
||||
</jms:listener-container>
|
||||
|
||||
<bean id="responder" class="org.springframework.integration.jms.config.JmsDynamicDestinationTests$Responder"/>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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 javax.jms.TextMessage;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageChannel;
|
||||
import org.springframework.integration.core.MessagingTemplate;
|
||||
import org.springframework.integration.core.PollableChannel;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @since 2.1
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class JmsDynamicDestinationTests {
|
||||
|
||||
@Autowired
|
||||
private MessageChannel channelAdapterChannel;
|
||||
|
||||
@Autowired
|
||||
private MessageChannel gatewayChannel;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel channelAdapterResults1;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel channelAdapterResults2;
|
||||
|
||||
|
||||
@Before
|
||||
public void prepareActiveMq() {
|
||||
ActiveMqTestUtils.prepare();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void channelAdapter() throws Exception {
|
||||
Message<?> message1 = MessageBuilder.withPayload("test-1").setHeader("destinationNumber", 1).build();
|
||||
Message<?> message2 = MessageBuilder.withPayload("test-2").setHeader("destinationNumber", 2).build();
|
||||
channelAdapterChannel.send(message1);
|
||||
channelAdapterChannel.send(message2);
|
||||
Message<?> result1 = channelAdapterResults1.receive(5000);
|
||||
Message<?> result2 = channelAdapterResults2.receive(5000);
|
||||
assertNotNull(result1);
|
||||
assertNotNull(result2);
|
||||
TextMessage jmsResult1 = (TextMessage) result1.getPayload();
|
||||
TextMessage jmsResult2 = (TextMessage) result2.getPayload();
|
||||
assertEquals("test-1", jmsResult1.getText());
|
||||
assertEquals("queue://queue.test.dynamic.adapter.1", jmsResult1.getJMSDestination().toString());
|
||||
assertEquals("test-2", jmsResult2.getText());
|
||||
assertEquals("queue://queue.test.dynamic.adapter.2", jmsResult2.getJMSDestination().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gateway() throws Exception {
|
||||
Message<?> message1 = MessageBuilder.withPayload("test-1").setHeader("destinationNumber", 1).build();
|
||||
Message<?> message2 = MessageBuilder.withPayload("test-2").setHeader("destinationNumber", 2).build();
|
||||
MessagingTemplate template = new MessagingTemplate();
|
||||
Message<?> result1 = template.sendAndReceive(gatewayChannel, message1);
|
||||
Message<?> result2 = template.sendAndReceive(gatewayChannel, message2);
|
||||
assertNotNull(result1);
|
||||
assertNotNull(result2);
|
||||
assertEquals("test-1!", result1.getPayload());
|
||||
assertEquals("test-2!!", result2.getPayload());
|
||||
}
|
||||
|
||||
|
||||
public static class Responder {
|
||||
|
||||
public String one(String message) {
|
||||
return message + "!";
|
||||
}
|
||||
|
||||
public String two(String message) {
|
||||
return message + "!!";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user