router polishing, minor changes to PayloadTypeRouter algorithm
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 <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.
|
||||
* <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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user