From bde9178a1fb3301830154aa5a216d6bdfe6c358e Mon Sep 17 00:00:00 2001 From: Iwein Fuld Date: Tue, 14 Apr 2009 17:20:51 +0000 Subject: [PATCH] INT-638 --- .../handler/MessageHandlerChain.java | 55 ++++++++++++------- spring-integration-reference/src/chain.xml | 22 ++++++-- 2 files changed, 54 insertions(+), 23 deletions(-) diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/handler/MessageHandlerChain.java b/org.springframework.integration/src/main/java/org/springframework/integration/handler/MessageHandlerChain.java index 0803ae8a51..9370a6e980 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/handler/MessageHandlerChain.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/handler/MessageHandlerChain.java @@ -43,16 +43,18 @@ import org.springframework.util.Assert; * It is expected that each handler will produce reply messages and send them to * its output channel, although this is not enforced. It is possible to filter * messages in the middle of the chain, for example using a - * {@link MessageFilter}. + * {@link MessageFilter}. A {@link MessageHandler} returning null will have the + * same effect, although this option is less expressive. *

* This component can be used from the namespace to improve the readability of * the configuration by removing channels that can be created implicitly. *

+ * *

  * <chain>
- *     <filter ref="someFilter"/>
- *     <bean class="SomeMessageHandlerImplementation"/>
- *     <transformer ref="someTransformer"/>
+ *     <filter ref="someFilter"/>
+ *     <bean class="SomeMessageHandlerImplementation"/>
+ *     <transformer ref="someTransformer"/>
  *     <aggregator ... />
  * </chain>
  * 
@@ -60,7 +62,8 @@ import org.springframework.util.Assert; * @author Mark Fisher * @author Iwein Fuld */ -public class MessageHandlerChain extends IntegrationObjectSupport implements MessageHandler { +public class MessageHandlerChain extends IntegrationObjectSupport implements + MessageHandler { private static final String OUTPUT_CHANNEL_PROPERTY = "outputChannel"; @@ -83,7 +86,9 @@ public class MessageHandlerChain extends IntegrationObjectSupport implements Mes public final void afterPropertiesSet() { synchronized (this.initializationMonitor) { if (!this.initialized) { - Assert.notEmpty(this.handlers, "handler list must not be empty"); + Assert + .notEmpty(this.handlers, + "handler list must not be empty"); this.configureChain(); this.initialized = true; } @@ -106,26 +111,33 @@ public class MessageHandlerChain extends IntegrationObjectSupport implements Mes MessageHandler handler = handlers.get(i); PropertyAccessor accessor = new BeanWrapperImpl(handler); if (!first) { - EventDrivenConsumer consumer = new EventDrivenConsumer(channel, handler); + EventDrivenConsumer consumer = new EventDrivenConsumer(channel, + handler); consumer.start(); } if (!last) { channel = new DirectChannel(); channel.setBeanName("_" + this + ".channel#" + i); - Assert.notNull(accessor.getPropertyType(OUTPUT_CHANNEL_PROPERTY), + Assert.notNull(accessor + .getPropertyType(OUTPUT_CHANNEL_PROPERTY), "All handlers except for the last one in the chain must implement property '" - + OUTPUT_CHANNEL_PROPERTY + "' of type 'MessageChannel'"); + + OUTPUT_CHANNEL_PROPERTY + + "' of type 'MessageChannel'"); accessor.setPropertyValue(OUTPUT_CHANNEL_PROPERTY, channel); } else if (accessor.getPropertyType(OUTPUT_CHANNEL_PROPERTY) != null) { MessageChannel replyChannel = (this.outputChannel != null) ? this.outputChannel : new ReplyForwardingMessageChannel(); - accessor.setPropertyValue(OUTPUT_CHANNEL_PROPERTY, replyChannel); + accessor + .setPropertyValue(OUTPUT_CHANNEL_PROPERTY, replyChannel); } else { - Assert.isNull(this.outputChannel, - "An output channel was provided, but the final handler in the chain does not implement property '" - + OUTPUT_CHANNEL_PROPERTY + "' of type 'MessageChannel'"); + Assert + .isNull( + this.outputChannel, + "An output channel was provided, but the final handler in the chain does not implement property '" + + OUTPUT_CHANNEL_PROPERTY + + "' of type 'MessageChannel'"); } } } @@ -143,21 +155,26 @@ public class MessageHandlerChain extends IntegrationObjectSupport implements Mes public boolean send(Message message, long timeout) { Object replyChannelHeader = message.getHeaders().getReplyChannel(); if (replyChannelHeader == null) { - throw new MessageHandlingException(message, "no replyChannel header available"); + throw new MessageHandlingException(message, + "no replyChannel header available"); } MessageChannel replyChannel = null; if (replyChannelHeader instanceof MessageChannel) { replyChannel = (MessageChannel) replyChannelHeader; } else if (replyChannelHeader instanceof String) { - Assert.notNull(getChannelResolver(), "ChannelResolver is required"); - replyChannel = getChannelResolver().resolveChannelName((String) replyChannelHeader); + Assert.notNull(getChannelResolver(), + "ChannelResolver is required"); + replyChannel = getChannelResolver().resolveChannelName( + (String) replyChannelHeader); } else { - throw new MessageHandlingException(message, "invalid replyChannel type [" - + replyChannelHeader.getClass() + "]"); + throw new MessageHandlingException(message, + "invalid replyChannel type [" + + replyChannelHeader.getClass() + "]"); } - return (timeout >= 0) ? replyChannel.send(message, timeout) : replyChannel.send(message); + return (timeout >= 0) ? replyChannel.send(message, timeout) + : replyChannel.send(message); } } } diff --git a/spring-integration-reference/src/chain.xml b/spring-integration-reference/src/chain.xml index d30ce746a6..8275146dd1 100644 --- a/spring-integration-reference/src/chain.xml +++ b/spring-integration-reference/src/chain.xml @@ -26,8 +26,20 @@ - The handler chain simplifies configuration while internally maintaining the same degree of loose coupling between - components, and it is trivial to modify the configuration if at some point a non-linear arrangement is required. + The handler chain simplifies configuration while internally maintaining the same degree of loose coupling between + components, and it is trivial to modify the configuration if at some point a non-linear arrangement is required. + The chain will be expanded into a linear setup of the listed endpoints, separated by direct + channels. The reply channel header will not be taken into account within the chain: only + after the last handler is invoked will the resulting message be forwarded onto the reply channel or the chain's output + channel. Because of this setup all handlers except the last require a setOutputChannel + implementation. The last handler only needs an output channel if the outputChannel on the MessageHandlerChain is set. + If this is not the case, the "replyChannel" header needs to be set on each message, so that it is clear where the + message needs to go. + + + In most cases there is no need to implement MessageHandlers yourself. The next section will focus on namespace + support for the chain element. Most Spring Integration enpoints like Service Activators and Transformers are + suitable for use within a MessageHandlerChain. @@ -36,7 +48,7 @@ The <chain> element provides an 'input-channel' attribute, and if the last element in the chain is capable of producing reply messages, it may optionally provide an 'output-channel' attribute. The sub-elements are then - filters, transformers, splitters, and service-activators. The last element may be a router. + filters, transformers, splitters, and service-activators. The last element may also be a router or aggregator. @@ -45,7 +57,9 @@ ]]> - The <header-enricher> used in the above example will set a message header with name "foo" and value "bar" on the message. + The <header-enricher> element used in the above example will set a message header with name "foo" and value "bar" on the message. + A header enricher is a specialization of Transformer that touches only header values. You could obtain the same result by + implementing a MessageHandler that did the header modifications and wiring that as a bean. \ No newline at end of file