router polishing, minor changes to PayloadTypeRouter algorithm

This commit is contained in:
Mark Fisher
2010-11-11 15:43:57 -05:00
parent 426c5713fd
commit c4a760a26d
4 changed files with 81 additions and 77 deletions

View File

@@ -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<Object> getChannelIdentifiers(Message<?> message) {
Object result = this.messageProcessor.processMessage(message);
List<Object> asList = new ArrayList<Object>();
asList.add(result);
return asList;
return Collections.singletonList(result);
}
}

View File

@@ -45,34 +45,38 @@ public class PayloadTypeRouter extends AbstractMessageRouter {
*/
@Override
protected List<Object> getChannelIdentifiers(Message<?> message) {
Class<?> firstInterfaceMatch = null;
String channelName = this.getChannelName(message);
return (channelName != null) ? Collections.<Object>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;

View File

@@ -35,62 +35,61 @@ import org.springframework.util.Assert;
* <p/>
* 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.
* <p/>
* 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.
* <p/>
* Contrary to a standard &lt;router .../&gt; 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 &lt;router .../&gt; 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.
* <p/>
* 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<Recipient> recipients;
private volatile List<Recipient> 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<MessageChannel> channels) {
Assert.notEmpty(channels, "channels must not be empty");
List<Recipient> recipients = new ArrayList<Recipient>();
for (MessageChannel channel : channels) {
recipients.add(new Recipient(channel));
}
this.setRecipients(recipients);
}
/**
* Set the recipients for this router.
*/
public void setRecipients(List<Recipient> 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<MessageChannel> channels) {
Assert.notEmpty(channels, "channels must not be empty");
List<Recipient> recipients = new ArrayList<Recipient>();
for (MessageChannel channel : channels) {
recipients.add(new Recipient(channel));
}
this.setRecipients(recipients);
}
/**
* Set the recipients for this router.
*/
public void setRecipients(List<Recipient> 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<Object> getChannelIdentifiers(Message<?> message) {
List<Object> channels = new ArrayList<Object>();
List<Recipient> 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);
}
}
}

View File

@@ -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<String, String> 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<String, String> namespaces = new HashMap<String, String>();
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<Object> 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);
}