All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.integration.router.RecipientListRouter Maven / Gradle / Ivy

There is a newer version: 6.3.3
Show newest version
/*
 * Copyright 2002-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.integration.router;

import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Collectors;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.integration.core.MessageSelector;
import org.springframework.integration.filter.ExpressionEvaluatingSelector;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.core.DestinationResolver;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/**
 * 
 * {@code
 * 
 *     
 *     
 * 
 * }
 * 
*

* 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. *

* For more advanced, programmatic control of dynamic recipient lists, consider * using the @Router annotation or extending {@link AbstractMappingMessageRouter} 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. *

* 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 * @author Artem Bilan * @author Liujiong * @author Gary Russell */ public class RecipientListRouter extends AbstractMessageRouter implements RecipientListRouterManagement { private volatile Queue recipients = new ConcurrentLinkedQueue<>(); /** * 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)}. * @param channels The channels. */ public void setChannels(List channels) { Assert.notEmpty(channels, "'channels' must not be empty"); setRecipients(channels.stream() .map(Recipient::new) .collect(Collectors.toList())); } /** * Set the recipients for this router. * @param recipients The recipients. */ public void setRecipients(List recipients) { Assert.notEmpty(recipients, "'recipients' must not be empty"); Queue newRecipients = new ConcurrentLinkedQueue<>(recipients); newRecipients.forEach(this::setupRecipient); if (logger.isDebugEnabled()) { logger.debug("Channel Recipients: " + this.recipients + " replaced with: " + newRecipients); } this.recipients = newRecipients; } /** * Set the recipients for this router. * @param recipientMappings map contains channelName and expression */ @Override @ManagedAttribute public void setRecipientMappings(Map recipientMappings) { Assert.notEmpty(recipientMappings, "'recipientMappings' must not be empty"); Assert.noNullElements(recipientMappings.keySet().toArray(), "'recipientMappings' cannot have null keys."); Queue newRecipients = new ConcurrentLinkedQueue<>(); for (Entry next : recipientMappings.entrySet()) { if (StringUtils.hasText(next.getValue())) { addRecipient(next.getKey(), next.getValue(), newRecipients); } else { addRecipient(next.getKey(), (MessageSelector) null, newRecipients); } } if (logger.isDebugEnabled()) { logger.debug("Channel Recipients: " + this.recipients + " replaced with: " + newRecipients); } this.recipients = newRecipients; } @Override @ManagedOperation public void addRecipient(String channelName, String selectorExpression) { addRecipient(channelName, selectorExpression, this.recipients); } private void addRecipient(String channelName, String selectorExpression, Queue recipientsToAdd) { Assert.hasText(channelName, "'channelName' must not be empty."); Assert.hasText(selectorExpression, "'selectorExpression' must not be empty."); ExpressionEvaluatingSelector expressionEvaluatingSelector = new ExpressionEvaluatingSelector(selectorExpression); expressionEvaluatingSelector.setBeanFactory(getBeanFactory()); Recipient recipient = new Recipient(channelName, expressionEvaluatingSelector); setupRecipient(recipient); recipientsToAdd.add(recipient); } @Override @ManagedOperation public void addRecipient(String channelName) { addRecipient(channelName, (MessageSelector) null); } public void addRecipient(String channelName, MessageSelector selector) { addRecipient(channelName, selector, this.recipients); } private void addRecipient(String channelName, MessageSelector selector, Queue recipientsToAdd) { Assert.hasText(channelName, "'channelName' must not be empty."); Recipient recipient = new Recipient(channelName, selector); setupRecipient(recipient); recipientsToAdd.add(recipient); } public void addRecipient(MessageChannel channel) { addRecipient(channel, null); } public void addRecipient(MessageChannel channel, MessageSelector selector) { Recipient recipient = new Recipient(channel, selector); setupRecipient(recipient); this.recipients.add(recipient); } private void setupRecipient(Recipient recipient) { BeanFactory beanFactory = getBeanFactory(); if (beanFactory != null) { recipient.setChannelResolver(getChannelResolver()); if (recipient.selector instanceof BeanFactoryAware) { ((BeanFactoryAware) recipient.selector).setBeanFactory(beanFactory); } } } @Override @ManagedOperation public int removeRecipient(String channelName) { int counter = 0; MessageChannel channel = getChannelResolver().resolveDestination(channelName); for (Iterator it = this.recipients.iterator(); it.hasNext(); ) { if (it.next().getChannel() == channel) { it.remove(); counter++; } } return counter; } @Override @ManagedOperation public int removeRecipient(String channelName, String selectorExpression) { int counter = 0; MessageChannel targetChannel = getChannelResolver().resolveDestination(channelName); for (Iterator it = this.recipients.iterator(); it.hasNext(); ) { Recipient next = it.next(); MessageSelector selector = next.getSelector(); MessageChannel channel = next.getChannel(); if (selector instanceof ExpressionEvaluatingSelector && channel.equals(targetChannel) && ((ExpressionEvaluatingSelector) selector).getExpressionString().equals(selectorExpression)) { it.remove(); counter++; } } return counter; } @Override @ManagedOperation public void replaceRecipients(Properties recipientMappings) { Assert.notEmpty(recipientMappings, "'recipientMappings' must not be empty"); Set keys = recipientMappings.stringPropertyNames(); Queue originalRecipients = this.recipients; this.recipients.clear(); for (String key : keys) { Assert.notNull(key, "channelName can't be null."); if (StringUtils.hasText(recipientMappings.getProperty(key))) { addRecipient(key, recipientMappings.getProperty(key)); } else { addRecipient(key); } } if (logger.isDebugEnabled()) { logger.debug("Channel Recipients:" + originalRecipients + " replaced with:" + this.recipients); } } @Override @ManagedAttribute public Collection getRecipients() { return Collections.unmodifiableCollection(this.recipients); } @Override public String getComponentType() { return "recipient-list-router"; } @Override protected Collection determineTargetChannels(Message message) { return this.recipients.stream() .filter(recipient -> recipient.accept(message)) .map(Recipient::getChannel) .collect(Collectors.toList()); } @Override protected void onInit() { super.onInit(); this.recipients.forEach(this::setupRecipient); } public static class Recipient { private final MessageSelector selector; private MessageChannel channel; private String channelName; private DestinationResolver channelResolver; public Recipient(MessageChannel channel) { this(channel, null); } public Recipient(MessageChannel channel, MessageSelector selector) { this.channel = channel; this.selector = selector; } public Recipient(String channelName) { this(channelName, null); } public Recipient(String channelName, MessageSelector selector) { this.channelName = channelName; this.selector = selector; } public void setChannelResolver(DestinationResolver channelResolver) { this.channelResolver = channelResolver; } private MessageSelector getSelector() { return this.selector; } public MessageChannel getChannel() { if (this.channel == null) { String channelNameForInitialization = this.channelName; if (channelNameForInitialization != null) { if (this.channelResolver != null) { this.channel = this.channelResolver.resolveDestination(channelNameForInitialization); this.channelName = null; } } } return this.channel; } public boolean accept(Message message) { return (this.selector == null || this.selector.accept(message)); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy