diff --git a/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMessageProcessingRouter.java b/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMessageProcessingRouter.java index adcaa76658..6bcd5011aa 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMessageProcessingRouter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMessageProcessingRouter.java @@ -16,7 +16,7 @@ package org.springframework.integration.router; -import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.springframework.beans.factory.BeanFactoryAware; @@ -42,6 +42,7 @@ class AbstractMessageProcessingRouter extends AbstractMessageRouter { this.messageProcessor = messageProcessor; } + @Override public final void onInit() { super.onInit(); @@ -56,9 +57,7 @@ class AbstractMessageProcessingRouter extends AbstractMessageRouter { @Override protected List getChannelIdentifiers(Message message) { Object result = this.messageProcessor.processMessage(message); - List asList = new ArrayList(); - asList.add(result); - return asList; + return Collections.singletonList(result); } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/router/PayloadTypeRouter.java b/spring-integration-core/src/main/java/org/springframework/integration/router/PayloadTypeRouter.java index 43c5abccd4..d2ade7c078 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/router/PayloadTypeRouter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/router/PayloadTypeRouter.java @@ -45,34 +45,38 @@ public class PayloadTypeRouter extends AbstractMessageRouter { */ @Override protected List getChannelIdentifiers(Message message) { - Class firstInterfaceMatch = null; + String channelName = this.getChannelName(message); + return (channelName != null) ? Collections.singletonList(channelName) : null; + } + + private String getChannelName(Message message) { Class type = message.getPayload().getClass(); while (type != null && !CollectionUtils.isEmpty(this.channelIdentifierMap)) { + // first, check for an exact type match + String channelName = this.channelIdentifierMap.get(type.getName()); + if (StringUtils.hasText(channelName)) { + return channelName; + } + // next, check for interfaces of this type + Class matchedInterface = null; Class[] interfaces = type.getInterfaces(); - // first try to find a match amongst the interfaces and also check if there is more than one - for (Class ifc : interfaces) { - if (this.channelIdentifierMap.containsKey(ifc.getName())) { - if (firstInterfaceMatch != null) { + for (Class currentInterface : interfaces) { + String currentChannelName = this.channelIdentifierMap.get(currentInterface.getName()); + if (StringUtils.hasText(currentChannelName)) { + if (matchedInterface != null) { throw new MessageHandlingException(message, "Unresolvable ambiguity while attempting to find closest match for [" + type.getName() + - "]. Candidate types [" + firstInterfaceMatch.getName() + "] and [" + - ifc.getName() + "] have equal weight."); - } - else { - firstInterfaceMatch = ifc; + "]. Candidate types [" + matchedInterface.getName() + "] and [" + + currentInterface.getName() + "] have equal weight."); } + matchedInterface = currentInterface; + channelName = currentChannelName; } } - // the actual type should favor the possible interface match - String channelName = this.channelIdentifierMap.get(type.getName()); - if (!StringUtils.hasText(channelName)) { - if (firstInterfaceMatch != null) { - return Collections.singletonList((Object) this.channelIdentifierMap.get(firstInterfaceMatch.getName())); - } - } - else { - return Collections.singletonList((Object)channelName); + if (channelName != null) { + return channelName; } + // finally, continue up the hierarchy type = type.getSuperclass(); } return null; diff --git a/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientListRouter.java b/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientListRouter.java index cb5635751e..f4a5da0cdb 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientListRouter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientListRouter.java @@ -35,62 +35,61 @@ import org.springframework.util.Assert; *

* A Message Router that sends Messages to a list of recipient channels. The * recipients can be provided as a static list of {@link MessageChannel} - * instances via the {@link #setChannels(List)} method, or for dynamic - * behavior, the values can be provided via the - * {@link #setRecipients(List)} method. + * instances via the {@link #setChannels(List)} method, or for dynamic behavior, + * the values can be provided via the {@link #setRecipients(List)} method. *

- * For more advanced, programmatic control - * of dynamic recipient lists, consider using the @Router annotation or - * extending {@link AbstractMessageRouter} instead. + * For more advanced, programmatic control of dynamic recipient lists, consider + * using the @Router annotation or extending {@link AbstractMessageRouter} instead. *

- * Contrary to a standard <router .../> this handler will try to send to all channels that are configured as - * recipients. It is to channels what a publish subscribe channel is to endpoints. + * Contrary to a standard <router .../> this handler will try to send to + * all channels that are configured as recipients. It is to channels what a + * publish subscribe channel is to endpoints. *

- * Using this class only makes sense if it is essential to send messages on multiple channels instead of - * sending them to multiple handlers. If the latter is an option using a publish subscribe channel is the more flexible - * solution. - * + * Using this class only makes sense if it is essential to send messages on + * multiple channels instead of sending them to multiple handlers. If the latter + * is an option using a publish subscribe channel is the more flexible solution. + * * @author Mark Fisher * @author Oleg Zhurakousky */ public class RecipientListRouter extends AbstractMessageRouter implements InitializingBean { - private volatile List recipients; - + private volatile List recipients; - /** - * Set the channels for this router. Either call this method or - * {@link #setRecipients(List)} but not both. If MessageSelectors - * should be considered, then use {@link #setRecipients(List)}. - */ - public void setChannels(List channels) { - Assert.notEmpty(channels, "channels must not be empty"); - List recipients = new ArrayList(); - for (MessageChannel channel : channels) { - recipients.add(new Recipient(channel)); - } - this.setRecipients(recipients); - } - /** - * Set the recipients for this router. - */ - public void setRecipients(List recipients) { - Assert.notEmpty(recipients, "recipients must not be empty"); - this.recipients = recipients; - } + /** + * Set the channels for this router. Either call this method or + * {@link #setRecipients(List)} but not both. If MessageSelectors should be + * considered, then use {@link #setRecipients(List)}. + */ + public void setChannels(List channels) { + Assert.notEmpty(channels, "channels must not be empty"); + List recipients = new ArrayList(); + for (MessageChannel channel : channels) { + recipients.add(new Recipient(channel)); + } + this.setRecipients(recipients); + } + + /** + * Set the recipients for this router. + */ + public void setRecipients(List recipients) { + Assert.notEmpty(recipients, "recipients must not be empty"); + this.recipients = recipients; + } @Override public String getComponentType() { return "recipient-list-router"; } - @Override - public final void onInit() { - Assert.notEmpty(this.recipients, "a non-empty recipient list is required"); - } - - @Override + @Override + public final void onInit() { + Assert.notEmpty(this.recipients, "recipient list must not be empty"); + } + + @Override protected List getChannelIdentifiers(Message message) { List channels = new ArrayList(); List recipientList = this.recipients; @@ -101,13 +100,15 @@ public class RecipientListRouter extends AbstractMessageRouter implements Initia } return channels; } - + + public static class Recipient { private final MessageChannel channel; private final MessageSelector selector; + public Recipient(MessageChannel channel) { this(channel, null); } @@ -117,12 +118,14 @@ public class RecipientListRouter extends AbstractMessageRouter implements Initia this.selector = selector; } - public boolean accept(Message message) { - return (this.selector != null ? this.selector.accept(message) : true); - } public MessageChannel getChannel() { return this.channel; } + + public boolean accept(Message message) { + return (this.selector != null ? this.selector.accept(message) : true); + } } + } diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/router/XPathRouter.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/router/XPathRouter.java index 92a301272f..234237f75e 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/router/XPathRouter.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/router/XPathRouter.java @@ -27,6 +27,7 @@ import org.springframework.integration.Message; import org.springframework.integration.router.AbstractMessageRouter; import org.springframework.integration.xml.DefaultXmlPayloadConverter; import org.springframework.integration.xml.XmlPayloadConverter; +import org.springframework.util.Assert; import org.springframework.xml.xpath.NodeMapper; import org.springframework.xml.xpath.XPathExpression; import org.springframework.xml.xpath.XPathExpressionFactory; @@ -54,6 +55,7 @@ public class XPathRouter extends AbstractMessageRouter { * @param namespaces map of namespaces with prefixes as the map keys */ public XPathRouter(String expression, Map namespaces) { + Assert.hasText(expression, "expression must not be empty"); this.xPathExpression = XPathExpressionFactory.createXPathExpression(expression, namespaces); } @@ -66,6 +68,7 @@ public class XPathRouter extends AbstractMessageRouter { * @param namespace namespace uri */ public XPathRouter(String expression, String prefix, String namespace) { + Assert.hasText(expression, "expression must not be empty"); Map namespaces = new HashMap(); namespaces.put(prefix, namespace); this.xPathExpression = XPathExpressionFactory.createXPathExpression(expression, namespaces); @@ -78,6 +81,7 @@ public class XPathRouter extends AbstractMessageRouter { * @param expression the XPath expression as a String */ public XPathRouter(String expression) { + Assert.hasText(expression, "expression must not be empty"); this.xPathExpression = XPathExpressionFactory.createXPathExpression(expression); } @@ -87,25 +91,19 @@ public class XPathRouter extends AbstractMessageRouter { * @param expression the XPath expression */ public XPathRouter(XPathExpression expression) { + Assert.notNull(expression, "expression must not be null"); this.xPathExpression = expression; } - protected XmlPayloadConverter getConverter() { - return this.converter; - } - /** * Specify the Converter to use when converting payloads prior to XPath evaluation. */ public void setConverter(XmlPayloadConverter converter) { + Assert.notNull(converter, "converter must not be null"); this.converter = converter; } - protected XPathExpression getXPathExpression() { - return this.xPathExpression; - } - public String getComponentType() { return "xml:xpath-router"; } @@ -113,8 +111,8 @@ public class XPathRouter extends AbstractMessageRouter { @Override @SuppressWarnings("unchecked") public List getChannelIdentifiers(Message message) { - Node node = getConverter().convertToNode(message.getPayload()); - return getXPathExpression().evaluate(node, this.nodeMapper); + Node node = this.converter.convertToNode(message.getPayload()); + return this.xPathExpression.evaluate(node, this.nodeMapper); }