INT-3312: Add Support for outputChannelName

JIRA: https://jira.springsource.org/browse/INT-3312

* Add `setOutputChannelName` to `AbstractReplyProducingMessageHandler` and `SourcePollingChannelAdapterFactoryBean`
to allow to have 'late binding' and resolve the real channel from `AC` on component initialization, instead of creation phase
* Add `setRequestChannelName` and `setReplyChannelName` to `ContentEnricher` for the same purpose
* Make `HeaderValueMessageProcessor` implementation `public`. It is useful for JavaConfig and DSL
* Polishing parsers to use classes, not their names as strings

INT-3312: PR comments

INT-3312: Polishing
This commit is contained in:
Artem Bilan
2014-03-04 23:11:08 +02:00
committed by Gary Russell
parent 5c68029a72
commit f0a1f81931
9 changed files with 79 additions and 22 deletions

View File

@@ -16,6 +16,7 @@
package org.springframework.integration.config;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
@@ -24,11 +25,13 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.SmartLifecycle;
import org.springframework.messaging.MessageChannel;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
import org.springframework.integration.scheduling.PollerMetadata;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.core.DestinationResolutionException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* FactoryBean for creating a SourcePollingChannelAdapter instance.
@@ -44,6 +47,8 @@ public class SourcePollingChannelAdapterFactoryBean implements FactoryBean<Sourc
private volatile MessageChannel outputChannel;
private volatile String outputChannelName;
private volatile PollerMetadata pollerMetadata;
private volatile boolean autoStartup = true;
@@ -76,6 +81,10 @@ public class SourcePollingChannelAdapterFactoryBean implements FactoryBean<Sourc
this.outputChannel = outputChannel;
}
public void setOutputChannelName(String outputChannelName) {
this.outputChannelName = outputChannelName;
}
public void setPollerMetadata(PollerMetadata pollerMetadata) {
this.pollerMetadata = pollerMetadata;
}
@@ -127,6 +136,18 @@ public class SourcePollingChannelAdapterFactoryBean implements FactoryBean<Sourc
return;
}
Assert.notNull(this.source, "source is required");
if (StringUtils.hasText(this.outputChannelName)) {
Assert.isNull(this.outputChannel, "'outputChannelName' and 'outputChannel' are mutually exclusive.");
try {
this.outputChannel = this.beanFactory.getBean(this.outputChannelName, MessageChannel.class);
}
catch (BeansException e) {
throw new DestinationResolutionException("Failed to look up MessageChannel with name '"
+ this.outputChannelName + "' in the BeanFactory.");
}
}
Assert.notNull(this.outputChannel, "outputChannel is required");
SourcePollingChannelAdapter spca = new SourcePollingChannelAdapter();
spca.setSource(this.source);

View File

@@ -25,8 +25,8 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.ExpressionFactoryBean;
import org.springframework.integration.config.IntegrationConfigUtils;
import org.springframework.integration.transformer.ContentEnricher;
import org.springframework.integration.transformer.support.ExpressionEvaluatingHeaderValueMessageProcessor;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
@@ -69,8 +69,7 @@ public class EnricherParser extends AbstractConsumerEndpointParser {
String name = subElement.getAttribute("name");
BeanDefinition expressionDefinition = IntegrationNamespaceUtils.createExpressionDefinitionFromValueOrExpression("value",
"expression", parserContext, subElement, true);
BeanDefinitionBuilder valueProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationConfigUtils.BASE_PACKAGE + ".transformer.support.ExpressionEvaluatingHeaderValueMessageProcessor");
BeanDefinitionBuilder valueProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(ExpressionEvaluatingHeaderValueMessageProcessor.class);
valueProcessorBuilder.addConstructorArgValue(expressionDefinition)
.addConstructorArgValue(subElement.getAttribute("type"));
IntegrationNamespaceUtils.setValueIfAttributeDefined(valueProcessorBuilder, subElement, "overwrite");

View File

@@ -29,10 +29,12 @@ import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.IntegrationConfigUtils;
import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.integration.expression.DynamicExpression;
import org.springframework.integration.transformer.HeaderEnricher;
import org.springframework.integration.transformer.support.ExpressionEvaluatingHeaderValueMessageProcessor;
import org.springframework.integration.transformer.support.MessageProcessingHeaderValueMessageProcessor;
import org.springframework.integration.transformer.support.StaticHeaderValueMessageProcessor;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
@@ -216,8 +218,7 @@ public abstract class HeaderEnricherParserSupport extends AbstractTransformerPar
}
Object headerValue = (headerType != null) ?
new TypedStringValue(value, headerType) : value;
valueProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationConfigUtils.BASE_PACKAGE + ".transformer.support.StaticHeaderValueMessageProcessor");
valueProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(StaticHeaderValueMessageProcessor.class);
valueProcessorBuilder.addConstructorArgValue(headerValue);
}
else if (isExpression) {
@@ -225,8 +226,7 @@ public abstract class HeaderEnricherParserSupport extends AbstractTransformerPar
parserContext.getReaderContext().error(
"The 'method' attribute cannot be used with the 'expression' attribute.", element);
}
valueProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationConfigUtils.BASE_PACKAGE + ".transformer.support.ExpressionEvaluatingHeaderValueMessageProcessor");
valueProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(ExpressionEvaluatingHeaderValueMessageProcessor.class);
if (expressionElement != null) {
BeanDefinitionBuilder dynamicExpressionBuilder = BeanDefinitionBuilder.genericBeanDefinition(DynamicExpression.class);
dynamicExpressionBuilder.addConstructorArgValue(expressionElement.getAttribute("key"));
@@ -244,16 +244,14 @@ public abstract class HeaderEnricherParserSupport extends AbstractTransformerPar
"The 'type' attribute cannot be used with an inner bean.", element);
}
if (hasMethod || isScript) {
valueProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationConfigUtils.BASE_PACKAGE + ".transformer.support.MessageProcessingHeaderValueMessageProcessor");
valueProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(MessageProcessingHeaderValueMessageProcessor.class);
valueProcessorBuilder.addConstructorArgValue(innerComponentDefinition);
if (hasMethod) {
valueProcessorBuilder.addConstructorArgValue(method);
}
}
else {
valueProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationConfigUtils.BASE_PACKAGE + ".transformer.support.StaticHeaderValueMessageProcessor");
valueProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(StaticHeaderValueMessageProcessor.class);
valueProcessorBuilder.addConstructorArgValue(innerComponentDefinition);
}
}
@@ -263,14 +261,12 @@ public abstract class HeaderEnricherParserSupport extends AbstractTransformerPar
"The 'type' attribute cannot be used with the 'ref' attribute.", element);
}
if (hasMethod) {
valueProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationConfigUtils.BASE_PACKAGE + ".transformer.support.MessageProcessingHeaderValueMessageProcessor");
valueProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(MessageProcessingHeaderValueMessageProcessor.class);
valueProcessorBuilder.addConstructorArgReference(ref);
valueProcessorBuilder.addConstructorArgValue(method);
}
else {
valueProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationConfigUtils.BASE_PACKAGE + ".transformer.support.StaticHeaderValueMessageProcessor");
valueProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(StaticHeaderValueMessageProcessor.class);
valueProcessorBuilder.addConstructorArgReference(ref);
}
}

View File

@@ -21,6 +21,7 @@ import java.util.List;
import org.aopalliance.aop.Advice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.integration.core.MessageProducer;
import org.springframework.integration.core.MessagingTemplate;
@@ -34,6 +35,7 @@ import org.springframework.messaging.core.DestinationResolver;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
* Base class for MessageHandlers that are capable of producing replies.
@@ -48,6 +50,8 @@ public abstract class AbstractReplyProducingMessageHandler extends AbstractMessa
private MessageChannel outputChannel;
private String outputChannelName;
private volatile boolean requiresReply = false;
private final MessagingTemplate messagingTemplate;
@@ -70,6 +74,10 @@ public abstract class AbstractReplyProducingMessageHandler extends AbstractMessa
this.outputChannel = outputChannel;
}
public void setOutputChannelName(String outputChannelName) {
this.outputChannelName = outputChannelName;
}
/**
* Set the timeout for sending reply Messages.
*
@@ -128,6 +136,16 @@ public abstract class AbstractReplyProducingMessageHandler extends AbstractMessa
protected final void onInit() {
if (this.getBeanFactory() != null) {
this.messagingTemplate.setBeanFactory(getBeanFactory());
if (StringUtils.hasText(this.outputChannelName)) {
Assert.isNull(this.outputChannel, "'outputChannelName' and 'outputChannel' are mutually exclusive.");
try {
this.outputChannel = this.getBeanFactory().getBean(this.outputChannelName, MessageChannel.class);
}
catch (BeansException e) {
throw new DestinationResolutionException("Failed to look up MessageChannel with name '"
+ this.outputChannelName + "' in the BeanFactory.");
}
}
}
if (!CollectionUtils.isEmpty(this.adviceChain)) {
ProxyFactory proxyFactory = new ProxyFactory(new AdvisedRequestHandler());
@@ -215,7 +233,7 @@ public abstract class AbstractReplyProducingMessageHandler extends AbstractMessa
* @param replyMessage the reply Message to send
* @param replyChannelHeaderValue the 'replyChannel' header value from the original request
*/
private final void sendReplyMessage(Message<?> replyMessage, final Object replyChannelHeaderValue) {
private void sendReplyMessage(Message<?> replyMessage, final Object replyChannelHeaderValue) {
if (logger.isDebugEnabled()) {
logger.debug("handler '" + this + "' sending reply Message: " + replyMessage);
}

View File

@@ -37,6 +37,7 @@ import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandlingException;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
* Content Enricher is a Message Transformer that can augment a message's payload
@@ -68,8 +69,12 @@ public class ContentEnricher extends AbstractReplyProducingMessageHandler implem
private volatile MessageChannel requestChannel;
private volatile String requestChannelName;
private volatile MessageChannel replyChannel;
private volatile String replyChannelName;
private volatile Gateway gateway = null;
private volatile Long requestTimeout;
@@ -123,6 +128,10 @@ public class ContentEnricher extends AbstractReplyProducingMessageHandler implem
this.requestChannel = requestChannel;
}
public void setRequestChannelName(String requestChannelName) {
this.requestChannelName = requestChannelName;
}
/**
* Sets the content enricher's reply channel. If not specified, yet the request
* channel is set, an anonymous reply channel will automatically created
@@ -134,6 +143,10 @@ public class ContentEnricher extends AbstractReplyProducingMessageHandler implem
this.replyChannel = replyChannel;
}
public void setReplyChannelName(String replyChannelName) {
this.replyChannelName = replyChannelName;
}
/**
* Set the timeout value for sending request messages. If not explicitly
* configured, the default is one second.
@@ -207,6 +220,16 @@ public class ContentEnricher extends AbstractReplyProducingMessageHandler implem
*/
@Override
protected void doInit() {
if (StringUtils.hasText(this.requestChannelName)) {
Assert.isNull(this.requestChannel, "'requestChannelName' and 'requestChannel' are mutually exclusive.");
this.requestChannel = this.getBeanFactory().getBean(this.requestChannelName, MessageChannel.class);
}
if (StringUtils.hasText(this.replyChannelName)) {
Assert.isNull(this.replyChannel, "'replyChannelName' and 'replyChannel' are mutually exclusive.");
this.replyChannel = this.getBeanFactory().getBean(this.replyChannelName, MessageChannel.class);
}
if (this.replyChannel != null) {
Assert.notNull(this.requestChannel, "If the replyChannel is set, then the requestChannel must not be null");
}

View File

@@ -21,7 +21,7 @@ package org.springframework.integration.transformer.support;
* @author Artem Bilan
* @since 3.0
*/
abstract class AbstractHeaderValueMessageProcessor<T> implements HeaderValueMessageProcessor<T> {
public abstract class AbstractHeaderValueMessageProcessor<T> implements HeaderValueMessageProcessor<T> {
// null indicates no explicit setting
private volatile Boolean overwrite = null;

View File

@@ -30,7 +30,7 @@ import org.springframework.messaging.Message;
* @author Artem Bilan
* @since 3.0
*/
class ExpressionEvaluatingHeaderValueMessageProcessor<T> extends AbstractHeaderValueMessageProcessor<T>
public class ExpressionEvaluatingHeaderValueMessageProcessor<T> extends AbstractHeaderValueMessageProcessor<T>
implements BeanFactoryAware {
private static final ExpressionParser expressionParser = new SpelExpressionParser(new SpelParserConfiguration(

View File

@@ -25,7 +25,7 @@ import org.springframework.messaging.Message;
* @author Artem Bilan
* @since 3.0
*/
class MessageProcessingHeaderValueMessageProcessor extends AbstractHeaderValueMessageProcessor<Object> {
public class MessageProcessingHeaderValueMessageProcessor extends AbstractHeaderValueMessageProcessor<Object> {
private final MessageProcessor<?> targetProcessor;

View File

@@ -23,7 +23,7 @@ import org.springframework.messaging.Message;
* @author Artem Bilan
* @since 3.0
*/
class StaticHeaderValueMessageProcessor<T> extends AbstractHeaderValueMessageProcessor<T> {
public class StaticHeaderValueMessageProcessor<T> extends AbstractHeaderValueMessageProcessor<T> {
private final T value;