From 1e0174b0cc36175c571646c3ac829d239126486d Mon Sep 17 00:00:00 2001 From: liujiong1982 Date: Sun, 20 Jul 2014 22:12:54 +0800 Subject: [PATCH 01/15] INT-2856:Add support for adding/removing individual recipients to the RecipientListRouter --- .../context/IntegrationObjectSupport.java | 4 + .../integration/router/RecipientHandler.java | 39 ++++++++ .../router/RecipientListRouter.java | 39 +++++++- ...rolBusRecipientListRouterTests-context.xml | 27 ++++++ .../ControlBusRecipientListRouterTests.java | 96 +++++++++++++++++++ 5 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 spring-integration-core/src/main/java/org/springframework/integration/router/RecipientHandler.java create mode 100644 spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml create mode 100644 spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java diff --git a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java index 9bf5f51ee1d..bd73eb8c862 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java @@ -81,6 +81,10 @@ public abstract class IntegrationObjectSupport implements BeanNameAware, NamedCo private volatile MessageBuilderFactory messageBuilderFactory; + public String getBeanName() { + return beanName; + } + @Override public final void setBeanName(String beanName) { this.beanName = beanName; diff --git a/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientHandler.java new file mode 100644 index 00000000000..9bf28f7fa15 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientHandler.java @@ -0,0 +1,39 @@ +/* + * Copyright 2014 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 + * + * http://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 org.springframework.integration.filter.ExpressionEvaluatingSelector; +import org.springframework.jmx.export.annotation.ManagedOperation; +import org.springframework.jmx.export.annotation.ManagedResource; + +/** + * @author Gary Russell + * @since 4.1 + * + */ +@ManagedResource +public interface RecipientHandler { + + @ManagedOperation + void addRecipient(String channelName, String expression); + + @ManagedOperation + void addRecipient(String channelName); + + @ManagedOperation + void removeRecipient(String channelName); + +} 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 b7ad5178b54..d03dd2a5f55 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 @@ -21,7 +21,11 @@ import java.util.List; import org.springframework.beans.factory.InitializingBean; +import org.springframework.integration.channel.AbstractMessageChannel; import org.springframework.integration.core.MessageSelector; +import org.springframework.integration.filter.ExpressionEvaluatingSelector; +import org.springframework.jmx.export.annotation.ManagedOperation; +import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.util.Assert; @@ -55,8 +59,10 @@ * @author Mark Fisher * @author Oleg Zhurakousky * @author Artem Bilan + * @author Liujiong */ -public class RecipientListRouter extends AbstractMessageRouter implements InitializingBean { +@ManagedResource +public class RecipientListRouter extends AbstractMessageRouter implements InitializingBean, RecipientHandler { private volatile List recipients; @@ -135,4 +141,35 @@ public boolean accept(Message message) { } } + + @Override + @ManagedOperation + public void addRecipient(String channelName, String selector) { + Assert.notNull(channelName, "channelName can't be null."); + MessageChannel channel = (MessageChannel) this.getBeanFactory().getBean(channelName); + ExpressionEvaluatingSelector expressionEvaluatingSelector = new ExpressionEvaluatingSelector(selector); + expressionEvaluatingSelector.setBeanFactory(this.getBeanFactory()); + recipients.add(new Recipient(channel,expressionEvaluatingSelector)); + } + + @Override + @ManagedOperation + public void addRecipient(String channelName) { + Assert.notNull(channelName, "channelName can't be null."); + MessageChannel channel = (MessageChannel) this.getBeanFactory().getBean(channelName); + recipients.add(new Recipient(channel)); + } + + @Override + @ManagedOperation + public void removeRecipient(String channelName) { + List removeList = new ArrayList(); + for (Recipient recipient : recipients) { + AbstractMessageChannel channel = (AbstractMessageChannel) recipient.getChannel(); + if (channel.getBeanName().equals(channelName)) { + removeList.add(recipient);//另外建立list + } + } + recipients.removeAll(removeList); + } } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml new file mode 100644 index 00000000000..c40ab6165e1 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java new file mode 100644 index 00000000000..e4c4d1fc6d0 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java @@ -0,0 +1,96 @@ +/* + * Copyright 2002-2014 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 + * + * http://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.config.xml; + +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.integration.core.MessagingTemplate; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.PollableChannel; +import org.springframework.messaging.support.GenericMessage; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +/** + * @author Liujiong + * @since 4.1 + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +@DirtiesContext +public class ControlBusRecipientListRouterTests { + + @Autowired + private MessageChannel input; + + @Autowired + private ConfigurableApplicationContext context; + + @Autowired + @Qualifier("routingChannelA") + private MessageChannel channel; + + @Test + public void testAddRecipient() { + context.start(); + MessagingTemplate messagingTemplate = new MessagingTemplate(); + messagingTemplate.setReceiveTimeout(1000); + messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.addRecipient('channel2','true')"); + Message message = new GenericMessage(1); + channel.send(message); + PollableChannel chanel1 = (PollableChannel) context.getBean("channel1"); + PollableChannel chanel2 = (PollableChannel) context.getBean("channel2"); + assertTrue(chanel1.receive(0).getPayload().equals(1)); + assertTrue(chanel2.receive(0).getPayload().equals(1)); + } + + @Test + public void testAddRecipientWithNullExpression() { + context.start(); + MessagingTemplate messagingTemplate = new MessagingTemplate(); + messagingTemplate.setReceiveTimeout(1000); + messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.addRecipient('channel2')"); + + Message message = new GenericMessage(1); + channel.send(message); + PollableChannel chanel1 = (PollableChannel) context.getBean("channel1"); + PollableChannel chanel2 = (PollableChannel) context.getBean("channel2"); + assertTrue(chanel1.receive(0).getPayload().equals(1)); + assertTrue(chanel2.receive(0).getPayload().equals(1)); + } + + @Test + public void testRemoveRecipient() { + context.start(); + MessagingTemplate messagingTemplate = new MessagingTemplate(); + messagingTemplate.setReceiveTimeout(1000); + messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.removeRecipient('channel2')"); + + Message message = new GenericMessage(1); + channel.send(message); + PollableChannel chanel1 = (PollableChannel) context.getBean("channel1"); + PollableChannel chanel2 = (PollableChannel) context.getBean("channel2"); + assertTrue(chanel1.receive(0).getPayload().equals(1)); + assertNull(chanel2.receive(0)); + } +} From e15d680299881d5126fee2fa417cf2ca458c0a62 Mon Sep 17 00:00:00 2001 From: liujiong1982 Date: Sun, 20 Jul 2014 22:29:03 +0800 Subject: [PATCH 02/15] INT-2856:Add support for adding/removing individual recipients to the RecipientListRouter --- .../springframework/integration/router/RecipientHandler.java | 3 +-- .../integration/router/RecipientListRouter.java | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientHandler.java index 9bf28f7fa15..b93d1e5e168 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientHandler.java @@ -15,12 +15,11 @@ */ package org.springframework.integration.router; -import org.springframework.integration.filter.ExpressionEvaluatingSelector; import org.springframework.jmx.export.annotation.ManagedOperation; import org.springframework.jmx.export.annotation.ManagedResource; /** - * @author Gary Russell + * @author Liujiong * @since 4.1 * */ 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 d03dd2a5f55..79e8e9577fe 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 @@ -61,7 +61,6 @@ * @author Artem Bilan * @author Liujiong */ -@ManagedResource public class RecipientListRouter extends AbstractMessageRouter implements InitializingBean, RecipientHandler { private volatile List recipients; From 010d98d4ad0a31f1cc9a9ecb589dcfed0fc34062 Mon Sep 17 00:00:00 2001 From: liujiong1982 Date: Tue, 22 Jul 2014 07:07:50 +0800 Subject: [PATCH 03/15] INT-2856:Add support for adding/removing individual recipients to the RecipientListRouter --- .../filter/ExpressionEvaluatingSelector.java | 22 +++++++++++++ .../integration/router/RecipientHandler.java | 3 ++ .../router/RecipientListRouter.java | 24 ++++++++++++-- ...rolBusRecipientListRouterTests-context.xml | 12 +++++++ .../ControlBusRecipientListRouterTests.java | 32 +++++++++++++++---- 5 files changed, 85 insertions(+), 8 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java b/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java index e1ab8a6a085..d05c1da2d4e 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java @@ -28,19 +28,41 @@ * The evaluation result of the expression must be a boolean value. * * @author Mark Fisher + * @author Liujiong * @since 2.0 */ public class ExpressionEvaluatingSelector extends AbstractMessageProcessingSelector { private static final ExpressionParser expressionParser = new SpelExpressionParser(new SpelParserConfiguration(true, true)); + private String expressionString; public ExpressionEvaluatingSelector(String expressionString) { super(new ExpressionEvaluatingMessageProcessor(expressionParser.parseExpression(expressionString), Boolean.class)); + this.expressionString = expressionString; } public ExpressionEvaluatingSelector(Expression expression) { super(new ExpressionEvaluatingMessageProcessor(expression, Boolean.class)); + this.expressionString = expression.getExpressionString(); } + public String getExpressionString() { + return expressionString; + } + + public boolean equals(ExpressionEvaluatingSelector o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (this != null ? !this.expressionString.equals(o.expressionString) : o.expressionString != null) { + return false; + } + + return true; + } + } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientHandler.java index b93d1e5e168..c46ae18ea2d 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientHandler.java @@ -34,5 +34,8 @@ public interface RecipientHandler { @ManagedOperation void removeRecipient(String channelName); + + @ManagedOperation + void removeRecipient(String channelName, String selector); } 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 79e8e9577fe..7231d695147 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 @@ -130,7 +130,10 @@ public Recipient(MessageChannel channel, MessageSelector selector) { this.selector = selector; } - + public MessageSelector getSelector() { + return selector; + } + public MessageChannel getChannel() { return this.channel; } @@ -166,7 +169,24 @@ public void removeRecipient(String channelName) { for (Recipient recipient : recipients) { AbstractMessageChannel channel = (AbstractMessageChannel) recipient.getChannel(); if (channel.getBeanName().equals(channelName)) { - removeList.add(recipient);//另外建立list + removeList.add(recipient); + } + } + recipients.removeAll(removeList); + } + + @Override + @ManagedOperation + public void removeRecipient(String channelName, String selector) { + List removeList = new ArrayList(); + for (Recipient recipient : recipients) { + AbstractMessageChannel channel = (AbstractMessageChannel) recipient.getChannel(); + if (channel.getBeanName().equals(channelName)) { + ExpressionEvaluatingSelector sourceExpressionEvaluatingSelector = (ExpressionEvaluatingSelector) recipient.getSelector(); + ExpressionEvaluatingSelector targetExpressionEvaluatingSelector = new ExpressionEvaluatingSelector(selector); + if (targetExpressionEvaluatingSelector.equals(sourceExpressionEvaluatingSelector)){ + removeList.add(recipient); + } } } recipients.removeAll(removeList); diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml index c40ab6165e1..ef6daf9cdac 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml @@ -24,4 +24,16 @@ + + + + + + + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java index e4c4d1fc6d0..6144adaef72 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java @@ -18,8 +18,11 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; + +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ConfigurableApplicationContext; @@ -69,14 +72,14 @@ public void testAddRecipientWithNullExpression() { context.start(); MessagingTemplate messagingTemplate = new MessagingTemplate(); messagingTemplate.setReceiveTimeout(1000); - messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.addRecipient('channel2')"); + messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.addRecipient('channel3')"); Message message = new GenericMessage(1); channel.send(message); PollableChannel chanel1 = (PollableChannel) context.getBean("channel1"); - PollableChannel chanel2 = (PollableChannel) context.getBean("channel2"); + PollableChannel chanel3 = (PollableChannel) context.getBean("channel3"); assertTrue(chanel1.receive(0).getPayload().equals(1)); - assertTrue(chanel2.receive(0).getPayload().equals(1)); + assertTrue(chanel3.receive(0).getPayload().equals(1)); } @Test @@ -84,13 +87,30 @@ public void testRemoveRecipient() { context.start(); MessagingTemplate messagingTemplate = new MessagingTemplate(); messagingTemplate.setReceiveTimeout(1000); - messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.removeRecipient('channel2')"); + messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.addRecipient('channel4')"); + messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.removeRecipient('channel4')"); Message message = new GenericMessage(1); channel.send(message); PollableChannel chanel1 = (PollableChannel) context.getBean("channel1"); - PollableChannel chanel2 = (PollableChannel) context.getBean("channel2"); + PollableChannel chanel4 = (PollableChannel) context.getBean("channel4"); + assertTrue(chanel1.receive(0).getPayload().equals(1)); + assertNull(chanel4.receive(0)); + } + + @Test + public void testRemoveRecipientWithNullExpression() { + context.start(); + MessagingTemplate messagingTemplate = new MessagingTemplate(); + messagingTemplate.setReceiveTimeout(1000); + messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.addRecipient('channel5','true')"); + messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.removeRecipient('channel5','true')"); + + Message message = new GenericMessage(1); + channel.send(message); + PollableChannel chanel1 = (PollableChannel) context.getBean("channel1"); + PollableChannel chanel5 = (PollableChannel) context.getBean("channel5"); assertTrue(chanel1.receive(0).getPayload().equals(1)); - assertNull(chanel2.receive(0)); + assertNull(chanel5.receive(0)); } } From 401851c26f72161c20f0bf16a780fa76aaf1c84b Mon Sep 17 00:00:00 2001 From: liujiong1982 Date: Tue, 22 Jul 2014 07:47:55 +0800 Subject: [PATCH 04/15] INT-2856:Add support for adding/removing individual recipients to the RecipientListRouter --- .../integration/router/RecipientListRouter.java | 15 +++++++-------- ...er.java => RecipientListRouterManagement.java} | 5 ++++- .../xml/ControlBusRecipientListRouterTests.java | 1 - 3 files changed, 11 insertions(+), 10 deletions(-) rename spring-integration-core/src/main/java/org/springframework/integration/router/{RecipientHandler.java => RecipientListRouterManagement.java} (86%) 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 7231d695147..a47b2894aa0 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 @@ -19,13 +19,13 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; import org.springframework.beans.factory.InitializingBean; import org.springframework.integration.channel.AbstractMessageChannel; import org.springframework.integration.core.MessageSelector; import org.springframework.integration.filter.ExpressionEvaluatingSelector; import org.springframework.jmx.export.annotation.ManagedOperation; -import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.util.Assert; @@ -61,10 +61,9 @@ * @author Artem Bilan * @author Liujiong */ -public class RecipientListRouter extends AbstractMessageRouter implements InitializingBean, RecipientHandler { - - private volatile List recipients; +public class RecipientListRouter extends AbstractMessageRouter implements InitializingBean, RecipientListRouterManagement { + private volatile ConcurrentLinkedQueue recipients; /** * Set the channels for this router. Either call this method or @@ -87,7 +86,7 @@ public void setChannels(List channels) { */ public void setRecipients(List recipients) { Assert.notEmpty(recipients, "recipients must not be empty"); - this.recipients = recipients; + this.recipients = new ConcurrentLinkedQueue(recipients); } @Override @@ -104,7 +103,7 @@ public void onInit() throws Exception { @Override protected Collection determineTargetChannels(Message message) { List channels = new ArrayList(); - List recipientList = this.recipients; + ConcurrentLinkedQueue recipientList = this.recipients; for (Recipient recipient : recipientList) { if (recipient.accept(message)) { channels.add(recipient.getChannel()); @@ -165,7 +164,7 @@ public void addRecipient(String channelName) { @Override @ManagedOperation public void removeRecipient(String channelName) { - List removeList = new ArrayList(); + ConcurrentLinkedQueue removeList = new ConcurrentLinkedQueue(); for (Recipient recipient : recipients) { AbstractMessageChannel channel = (AbstractMessageChannel) recipient.getChannel(); if (channel.getBeanName().equals(channelName)) { @@ -178,7 +177,7 @@ public void removeRecipient(String channelName) { @Override @ManagedOperation public void removeRecipient(String channelName, String selector) { - List removeList = new ArrayList(); + ConcurrentLinkedQueue removeList = new ConcurrentLinkedQueue(); for (Recipient recipient : recipients) { AbstractMessageChannel channel = (AbstractMessageChannel) recipient.getChannel(); if (channel.getBeanName().equals(channelName)) { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientListRouterManagement.java similarity index 86% rename from spring-integration-core/src/main/java/org/springframework/integration/router/RecipientHandler.java rename to spring-integration-core/src/main/java/org/springframework/integration/router/RecipientListRouterManagement.java index c46ae18ea2d..b882ac86906 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientListRouterManagement.java @@ -19,12 +19,15 @@ import org.springframework.jmx.export.annotation.ManagedResource; /** + * Exposes adding/removing individual recipients operations for + * RecipientListRouter. This can be used with a control-bus and JMX. + * * @author Liujiong * @since 4.1 * */ @ManagedResource -public interface RecipientHandler { +public interface RecipientListRouterManagement { @ManagedOperation void addRecipient(String channelName, String expression); diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java index 6144adaef72..95c2b32530b 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java @@ -19,7 +19,6 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; From b006eac265479ad767c7013843c139c284604b29 Mon Sep 17 00:00:00 2001 From: liujiong1982 Date: Tue, 22 Jul 2014 21:05:41 +0800 Subject: [PATCH 05/15] INT-2856:Add support for adding/removing individual recipients to the RecipientListRouter --- .../integration/router/RecipientListRouter.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 a47b2894aa0..aa075137e45 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 @@ -182,8 +182,7 @@ public void removeRecipient(String channelName, String selector) { AbstractMessageChannel channel = (AbstractMessageChannel) recipient.getChannel(); if (channel.getBeanName().equals(channelName)) { ExpressionEvaluatingSelector sourceExpressionEvaluatingSelector = (ExpressionEvaluatingSelector) recipient.getSelector(); - ExpressionEvaluatingSelector targetExpressionEvaluatingSelector = new ExpressionEvaluatingSelector(selector); - if (targetExpressionEvaluatingSelector.equals(sourceExpressionEvaluatingSelector)){ + if (sourceExpressionEvaluatingSelector.getExpressionString().equals(selector)){ removeList.add(recipient); } } From 4e194fee7b5107627eb27074a989456f906bd82d Mon Sep 17 00:00:00 2001 From: liujiong1982 Date: Wed, 23 Jul 2014 14:05:15 +0800 Subject: [PATCH 06/15] INT-2856 Add comment, hashcode and some format change --- .../filter/ExpressionEvaluatingSelector.java | 4 ++++ .../router/RecipientListRouter.java | 12 +++++++--- .../router/RecipientListRouterManagement.java | 22 +++++++++++++++++-- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java b/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java index d05c1da2d4e..92e6d1512ba 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java @@ -65,4 +65,8 @@ public boolean equals(ExpressionEvaluatingSelector o) { return true; } + public int hashCode() { + return expressionString.hashCode(); + } + } 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 aa075137e45..fb087ced141 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 @@ -163,30 +163,36 @@ public void addRecipient(String channelName) { @Override @ManagedOperation - public void removeRecipient(String channelName) { + public int removeRecipient(String channelName) { + int counter = 0; ConcurrentLinkedQueue removeList = new ConcurrentLinkedQueue(); for (Recipient recipient : recipients) { AbstractMessageChannel channel = (AbstractMessageChannel) recipient.getChannel(); if (channel.getBeanName().equals(channelName)) { removeList.add(recipient); + counter++; } } recipients.removeAll(removeList); + return counter; } @Override @ManagedOperation - public void removeRecipient(String channelName, String selector) { + public int removeRecipient(String channelName, String selector) { + int counter = 0; ConcurrentLinkedQueue removeList = new ConcurrentLinkedQueue(); for (Recipient recipient : recipients) { AbstractMessageChannel channel = (AbstractMessageChannel) recipient.getChannel(); if (channel.getBeanName().equals(channelName)) { ExpressionEvaluatingSelector sourceExpressionEvaluatingSelector = (ExpressionEvaluatingSelector) recipient.getSelector(); - if (sourceExpressionEvaluatingSelector.getExpressionString().equals(selector)){ + if (sourceExpressionEvaluatingSelector.getExpressionString().equals(selector)) { removeList.add(recipient); + counter++; } } } recipients.removeAll(removeList); + return counter; } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientListRouterManagement.java b/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientListRouterManagement.java index b882ac86906..9fde0370108 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientListRouterManagement.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientListRouterManagement.java @@ -29,16 +29,34 @@ @ManagedResource public interface RecipientListRouterManagement { + /** + * Add a recipent with channelName and expression. + * @param channelName The channel name. + * @param expression The expression to filter the incoming message + */ @ManagedOperation void addRecipient(String channelName, String expression); + /** + * Add a recipent with channelName. + * @param channelName The channel name. + */ @ManagedOperation void addRecipient(String channelName); + /** + * Remove all recipients that match the channelName. + * @param channelName The channel name. + */ @ManagedOperation - void removeRecipient(String channelName); + int removeRecipient(String channelName); + /** + * Remove all recipients that match the channelName and expression + * @param channelName The channel name. + * @param expression The expression to filter the incoming message + */ @ManagedOperation - void removeRecipient(String channelName, String selector); + int removeRecipient(String channelName, String expression); } From 868b1ce6eaba4d8235763cc96daf0d539dc079de Mon Sep 17 00:00:00 2001 From: David Liu Date: Wed, 30 Jul 2014 17:22:33 +0800 Subject: [PATCH 07/15] INT-2856: fix broken test --- .../router/RecipientListRouterTests.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/spring-integration-core/src/test/java/org/springframework/integration/router/RecipientListRouterTests.java b/spring-integration-core/src/test/java/org/springframework/integration/router/RecipientListRouterTests.java index 5b6a0dc7255..ad88e2b62af 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/router/RecipientListRouterTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/router/RecipientListRouterTests.java @@ -16,12 +16,17 @@ package org.springframework.integration.router; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; import org.junit.Test; import org.mockito.Mockito; @@ -58,11 +63,11 @@ public void channelConfig() { router.setChannels(channels); router.setBeanFactory(mock(BeanFactory.class)); router.afterPropertiesSet(); - List recipients = (List) + ConcurrentLinkedQueue recipients = (ConcurrentLinkedQueue) new DirectFieldAccessor(router).getPropertyValue("recipients"); assertEquals(2, recipients.size()); - assertEquals(channel1, new DirectFieldAccessor(recipients.get(0)).getPropertyValue("channel")); - assertEquals(channel2, new DirectFieldAccessor(recipients.get(1)).getPropertyValue("channel")); + assertEquals(channel1, new DirectFieldAccessor(recipients.poll()).getPropertyValue("channel")); + assertEquals(channel2, new DirectFieldAccessor(recipients.poll()).getPropertyValue("channel")); } @Test From bb1fdee668da45baffd3b8864f38cad3d894ba74 Mon Sep 17 00:00:00 2001 From: David Liu Date: Thu, 31 Jul 2014 20:59:50 +0800 Subject: [PATCH 08/15] INT-2856: optimize code and add 3 new managed interface in RecipientListRouter --- .../filter/ExpressionEvaluatingSelector.java | 31 ++-- .../router/RecipientListRouter.java | 169 +++++++++++------- .../router/RecipientListRouterManagement.java | 48 +++-- ...rolBusRecipientListRouterTests-context.xml | 8 + .../ControlBusRecipientListRouterTests.java | 70 +++++++- 5 files changed, 228 insertions(+), 98 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java b/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java index 92e6d1512ba..6f71500e9e0 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java @@ -26,7 +26,7 @@ /** * A {@link MessageSelector} implementation that evaluates a SpEL expression. * The evaluation result of the expression must be a boolean value. - * + * * @author Mark Fisher * @author Liujiong * @since 2.0 @@ -35,7 +35,7 @@ public class ExpressionEvaluatingSelector extends AbstractMessageProcessingSelec private static final ExpressionParser expressionParser = new SpelExpressionParser(new SpelParserConfiguration(true, true)); - private String expressionString; + private final String expressionString; public ExpressionEvaluatingSelector(String expressionString) { super(new ExpressionEvaluatingMessageProcessor(expressionParser.parseExpression(expressionString), Boolean.class)); @@ -51,22 +51,15 @@ public String getExpressionString() { return expressionString; } - public boolean equals(ExpressionEvaluatingSelector o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - if (this != null ? !this.expressionString.equals(o.expressionString) : o.expressionString != null) { - return false; - } - - return true; + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("ExpressionEvaluatingSelector [expressionParser=") + .append(expressionParser.toString()) + .append(", expressionString=") + .append(this.expressionString) + .append("]"); + return builder.toString(); } - - public int hashCode() { - return expressionString.hashCode(); - } - + } 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 fb087ced141..2abdc45d5bf 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 @@ -18,18 +18,26 @@ import java.util.ArrayList; 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.Set; import java.util.concurrent.ConcurrentLinkedQueue; import org.springframework.beans.factory.InitializingBean; -import org.springframework.integration.channel.AbstractMessageChannel; 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.util.Assert; +import reactor.util.StringUtils; + /** *
  * {@code
@@ -61,9 +69,10 @@
  * @author Artem Bilan
  * @author Liujiong
  */
-public class RecipientListRouter extends AbstractMessageRouter implements InitializingBean, RecipientListRouterManagement {
+public class RecipientListRouter extends AbstractMessageRouter
+	implements InitializingBean, RecipientListRouterManagement {
 
-	private volatile ConcurrentLinkedQueue recipients;
+	private final ConcurrentLinkedQueue recipients = new ConcurrentLinkedQueue();
 
 	/**
 	 * Set the channels for this router. Either call this method or
@@ -86,7 +95,28 @@ public void setChannels(List channels) {
 	 */
 	public void setRecipients(List recipients) {
 		Assert.notEmpty(recipients, "recipients must not be empty");
-		this.recipients = new ConcurrentLinkedQueue(recipients);
+		this.recipients.addAll(recipients);
+	}
+
+	/**
+	 * 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");
+		this.recipients.clear();
+		for(Iterator> it = recipientMappings.entrySet().iterator(); it.hasNext();) {
+			Entry next = it.next();
+			if(StringUtils.hasText(next.getValue())) {
+				this.addRecipient(next.getKey(), next.getValue());
+			}
+			else {
+				this.addRecipient(next.getKey());
+			}
+
+		}
 	}
 
 	@Override
@@ -103,8 +133,7 @@ public void onInit() throws Exception {
 	@Override
 	protected Collection determineTargetChannels(Message message) {
 		List channels = new ArrayList();
-		ConcurrentLinkedQueue recipientList = this.recipients;
-		for (Recipient recipient : recipientList) {
+		for (Recipient recipient : this.recipients) {
 			if (recipient.accept(message)) {
 				channels.add(recipient.getChannel());
 			}
@@ -112,87 +141,105 @@ protected Collection determineTargetChannels(Message message)
 		return channels;
 	}
 
-
-	public static class Recipient {
-
-		private final MessageChannel channel;
-
-		private final MessageSelector selector;
-
-
-		public Recipient(MessageChannel channel) {
-			this(channel, null);
-		}
-
-		public Recipient(MessageChannel channel, MessageSelector selector) {
-			this.channel = channel;
-			this.selector = selector;
-		}
-
-		public MessageSelector getSelector() {
-			return selector;
-		}
-		
-		public MessageChannel getChannel() {
-			return this.channel;
-		}
-
-		public boolean accept(Message message) {
-			return (this.selector == null || this.selector.accept(message));
-		}
-	}
-
-
 	@Override
 	@ManagedOperation
-	public void addRecipient(String channelName, String selector) {
+	public void addRecipient(String channelName, String selectorExpression) {
 		Assert.notNull(channelName, "channelName can't be null.");
-		MessageChannel channel = (MessageChannel) this.getBeanFactory().getBean(channelName);
-		ExpressionEvaluatingSelector expressionEvaluatingSelector = new ExpressionEvaluatingSelector(selector);
+		MessageChannel channel = this.getBeanFactory().getBean(channelName, MessageChannel.class);
+		ExpressionEvaluatingSelector expressionEvaluatingSelector = new ExpressionEvaluatingSelector(selectorExpression);
 		expressionEvaluatingSelector.setBeanFactory(this.getBeanFactory());
-		recipients.add(new Recipient(channel,expressionEvaluatingSelector));
+		this.recipients.add(new Recipient(channel, expressionEvaluatingSelector));
 	}
 
 	@Override
 	@ManagedOperation
 	public void addRecipient(String channelName) {
 		Assert.notNull(channelName, "channelName can't be null.");
-		MessageChannel channel = (MessageChannel) this.getBeanFactory().getBean(channelName);
-		recipients.add(new Recipient(channel));
+		MessageChannel channel = this.getBeanFactory().getBean(channelName, MessageChannel.class);
+		this.recipients.add(new Recipient(channel));
 	}
 
 	@Override
 	@ManagedOperation
 	public int removeRecipient(String channelName) {
 		int counter = 0;
-		ConcurrentLinkedQueue removeList = new ConcurrentLinkedQueue();
-		for (Recipient recipient : recipients) {
-			AbstractMessageChannel channel = (AbstractMessageChannel) recipient.getChannel();
-			if (channel.getBeanName().equals(channelName)) {
-				removeList.add(recipient);
+		for (Iterator it = this.recipients.iterator();it.hasNext();) {
+			if (it.next().getChannel().equals(this.getBeanFactory().getBean(channelName))) {
+				it.remove();
 				counter++;
 			}
 		}
-		recipients.removeAll(removeList);
 		return counter;
 	}
-	
+
 	@Override
 	@ManagedOperation
-	public int removeRecipient(String channelName, String selector) {
+	public int removeRecipient(String channelName, String selectorExpression) {
 		int counter = 0;
-		ConcurrentLinkedQueue removeList = new ConcurrentLinkedQueue();
-		for (Recipient recipient : recipients) {
-			AbstractMessageChannel channel = (AbstractMessageChannel) recipient.getChannel();
-			if (channel.getBeanName().equals(channelName)) {
-				ExpressionEvaluatingSelector sourceExpressionEvaluatingSelector = (ExpressionEvaluatingSelector) recipient.getSelector();
-				if (sourceExpressionEvaluatingSelector.getExpressionString().equals(selector)) {
-					removeList.add(recipient);
-					counter++;
-				}
+		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(this.getBeanFactory().getBean(channelName)) &&
+					((ExpressionEvaluatingSelector)selector).getExpressionString().equals(selectorExpression)) {
+				it.remove();
+				counter++;
 			}
 		}
-		recipients.removeAll(removeList);
 		return counter;
 	}
+
+	@Override
+	@ManagedAttribute
+	public Collection getRecipients() {
+		  return Collections.unmodifiableCollection(this.recipients);
+	}
+
+	@Override
+	@ManagedOperation
+	public void replaceRecipients(Properties recipientMappings) {
+		Assert.notNull(recipientMappings, "'recipientMappings' must not be null");
+		Set keys = recipientMappings.stringPropertyNames();
+		this.recipients.clear();
+		for (String key : keys) {
+			Assert.notNull(key, "channelName can't be null.");
+			if(StringUtils.hasText(recipientMappings.getProperty(key))) {
+				this.addRecipient(key, recipientMappings.getProperty(key));
+			}
+			else {
+				this.addRecipient(key);
+			}
+		}
+	}
+
+
+	public static class Recipient {
+
+		private final MessageChannel channel;
+
+		private final MessageSelector selector;
+
+
+		public Recipient(MessageChannel channel) {
+			this(channel, null);
+		}
+
+		public Recipient(MessageChannel channel, MessageSelector selector) {
+			this.channel = channel;
+			this.selector = selector;
+		}
+
+		private MessageSelector getSelector() {
+			return selector;
+		}
+
+		public MessageChannel getChannel() {
+			return this.channel;
+		}
+
+		public boolean accept(Message message) {
+			return (this.selector == null || this.selector.accept(message));
+		}
+	}
 }
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientListRouterManagement.java b/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientListRouterManagement.java
index 9fde0370108..a02e371204d 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientListRouterManagement.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientListRouterManagement.java
@@ -15,13 +15,19 @@
  */
 package org.springframework.integration.router;
 
+import java.util.Collection;
+import java.util.Map;
+import java.util.Properties;
+
+import org.springframework.integration.router.RecipientListRouter.Recipient;
+import org.springframework.jmx.export.annotation.ManagedAttribute;
 import org.springframework.jmx.export.annotation.ManagedOperation;
 import org.springframework.jmx.export.annotation.ManagedResource;
 
 /**
- * Exposes adding/removing individual recipients operations for 
+ * Exposes adding/removing individual recipients operations for
  * RecipientListRouter. This can be used with a control-bus and JMX.
- * 
+ *
  * @author Liujiong
  * @since 4.1
  *
@@ -30,20 +36,20 @@
 public interface RecipientListRouterManagement {
 
 	/**
-	 * Add a recipent with channelName and expression.
+	 * Add a recipient with channelName and expression.
 	 * @param channelName The channel name.
-	 * @param expression The expression to filter the incoming message
+	 * @param expression The expression to filter the incoming message.
 	 */
 	@ManagedOperation
-	void addRecipient(String channelName, String expression);
-	
+	void addRecipient(String channelName, String selectorExpression);
+
 	/**
-	 * Add a recipent with channelName.
+	 * Add a recipient with channelName.
 	 * @param channelName The channel name.
 	 */
 	@ManagedOperation
 	void addRecipient(String channelName);
-	
+
 	/**
 	 * Remove all recipients that match the channelName.
 	 * @param channelName The channel name.
@@ -52,11 +58,31 @@ public interface RecipientListRouterManagement {
 	int removeRecipient(String channelName);
 
 	/**
-	 * Remove all recipients that match the channelName and expression
+	 * Remove all recipients that match the channelName and expression.
 	 * @param channelName The channel name.
 	 * @param expression The expression to filter the incoming message
 	 */
 	@ManagedOperation
-	int removeRecipient(String channelName, String expression);
-	
+	int removeRecipient(String channelName, String selectorExpression);
+
+	/**
+	 * @return an unmodifiable collection of recipients.
+	 */
+	@ManagedAttribute
+	Collection getRecipients();
+
+	/**
+	 * Replace recipient.
+	 * @param recipientMappings contain channelName and expression.
+	 */
+	@ManagedOperation
+	void replaceRecipients(Properties recipientMappings);
+
+	/**
+	 * Set recipients.
+	 * @param recipientMappings contain channelName and expression.
+	 */
+	@ManagedAttribute
+	void setRecipientMappings(Map recipientMappings);
+
 }
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml
index ef6daf9cdac..c87e1522dcc 100644
--- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml
+++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml
@@ -36,4 +36,12 @@
 		
 	
 	
+	
+		
+	
+	
+	
+		
+	
+	
 
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java
index 95c2b32530b..26a9a856c1a 100644
--- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java
+++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java
@@ -16,9 +16,16 @@
 
 package org.springframework.integration.config.xml;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -26,11 +33,14 @@
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.integration.core.MessagingTemplate;
+import org.springframework.integration.router.RecipientListRouter.Recipient;
+import org.springframework.integration.support.MessageBuilder;
 import org.springframework.messaging.Message;
 import org.springframework.messaging.MessageChannel;
 import org.springframework.messaging.PollableChannel;
 import org.springframework.messaging.support.GenericMessage;
 import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.annotation.DirtiesContext.ClassMode;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 /**
@@ -39,12 +49,15 @@
  */
 @ContextConfiguration
 @RunWith(SpringJUnit4ClassRunner.class)
-@DirtiesContext
+@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
 public class ControlBusRecipientListRouterTests {
 
 	@Autowired
 	private MessageChannel input;
 
+	@Autowired
+	private PollableChannel output;
+
 	@Autowired
 	private ConfigurableApplicationContext context;
 
@@ -52,9 +65,13 @@ public class ControlBusRecipientListRouterTests {
 	@Qualifier("routingChannelA")
 	private MessageChannel channel;
 
+	@Before
+	public  void aa(){
+		context.start();
+	}
+
 	@Test
 	public void testAddRecipient() {
-		context.start();
 		MessagingTemplate messagingTemplate = new MessagingTemplate();
 		messagingTemplate.setReceiveTimeout(1000);
 		messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.addRecipient('channel2','true')");
@@ -68,7 +85,6 @@ public void testAddRecipient() {
 
 	@Test
 	public void testAddRecipientWithNullExpression() {
-		context.start();
 		MessagingTemplate messagingTemplate = new MessagingTemplate();
 		messagingTemplate.setReceiveTimeout(1000);
 		messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.addRecipient('channel3')");
@@ -80,10 +96,9 @@ public void testAddRecipientWithNullExpression() {
 		assertTrue(chanel1.receive(0).getPayload().equals(1));
 		assertTrue(chanel3.receive(0).getPayload().equals(1));
 	}
-	
+
 	@Test
 	public void testRemoveRecipient() {
-		context.start();
 		MessagingTemplate messagingTemplate = new MessagingTemplate();
 		messagingTemplate.setReceiveTimeout(1000);
 		messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.addRecipient('channel4')");
@@ -96,10 +111,9 @@ public void testRemoveRecipient() {
 		assertTrue(chanel1.receive(0).getPayload().equals(1));
 		assertNull(chanel4.receive(0));
 	}
-	
+
 	@Test
 	public void testRemoveRecipientWithNullExpression() {
-		context.start();
 		MessagingTemplate messagingTemplate = new MessagingTemplate();
 		messagingTemplate.setReceiveTimeout(1000);
 		messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.addRecipient('channel5','true')");
@@ -112,4 +126,46 @@ public void testRemoveRecipientWithNullExpression() {
 		assertTrue(chanel1.receive(0).getPayload().equals(1));
 		assertNull(chanel5.receive(0));
 	}
+
+	@Test
+	public void testGetRecipients() {
+		MessagingTemplate messagingTemplate = new MessagingTemplate();
+		messagingTemplate.setReceiveTimeout(1000);
+		messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.getRecipients()");
+		Message result = this.output.receive(0);
+		Collection mappings = (Collection) result.getPayload();
+		assertEquals(context.getBean("channel1"), mappings.iterator().next().getChannel());
+	}
+
+	@Test
+	public void testSetRecipients() {
+		MessagingTemplate messagingTemplate = new MessagingTemplate();
+		messagingTemplate.setReceiveTimeout(1000);
+
+		Map map = new HashMap();map.put("channel6","true");
+		Message message = MessageBuilder.withPayload("@'simpleRouter.handler'.setRecipientMappings(headers.recipientMap)").setHeader("recipientMap", map).build();
+		this.input.send(message);
+		message = new GenericMessage(1);
+		channel.send(message);
+		PollableChannel chanel1 = (PollableChannel) context.getBean("channel1");
+		PollableChannel chanel6 = (PollableChannel) context.getBean("channel6");
+		assertNull(chanel1.receive(0));
+		assertTrue(chanel6.receive(0).getPayload().equals(1));
+	}
+
+	@Test
+	public void testReplaceRecipients() {
+		MessagingTemplate messagingTemplate = new MessagingTemplate();
+		messagingTemplate.setReceiveTimeout(1000);
+		Properties prop = new Properties();
+		prop.setProperty("channel7", "true");
+
+		messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.replaceRecipients('channel7=true')");
+		Message  message = new GenericMessage(1);
+		channel.send(message);
+		PollableChannel chanel1 = (PollableChannel) context.getBean("channel1");
+		PollableChannel chanel7 = (PollableChannel) context.getBean("channel7");
+		assertNull(chanel1.receive(0));
+		assertTrue(chanel7.receive(0).getPayload().equals(1));
+	}
 }

From 89dfa83e6da9c6c03b0b09a75f7ed997d60851fb Mon Sep 17 00:00:00 2001
From: David Liu 
Date: Fri, 1 Aug 2014 17:49:25 +0800
Subject: [PATCH 09/15] INT-2856: change as Artem's comments

---
 .../context/IntegrationObjectSupport.java       |  4 ----
 .../filter/ExpressionEvaluatingSelector.java    |  8 +-------
 .../integration/router/RecipientListRouter.java | 17 ++++++++++++++++-
 3 files changed, 17 insertions(+), 12 deletions(-)

diff --git a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java
index bd73eb8c862..9bf5f51ee1d 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java
@@ -81,10 +81,6 @@ public abstract class IntegrationObjectSupport implements BeanNameAware, NamedCo
 
 	private volatile MessageBuilderFactory messageBuilderFactory;
 
-	public String getBeanName() {
-		return beanName;
-	}
-	
 	@Override
 	public final void setBeanName(String beanName) {
 		this.beanName = beanName;
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java b/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java
index 6f71500e9e0..f19eb91c766 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/filter/ExpressionEvaluatingSelector.java
@@ -53,13 +53,7 @@ public String getExpressionString() {
 
 	@Override
 	public String toString() {
-		StringBuilder builder = new StringBuilder();
-		builder.append("ExpressionEvaluatingSelector [expressionParser=")
-			.append(expressionParser.toString())
-			.append(", expressionString=")
-			.append(this.expressionString)
-			.append("]");
-		return builder.toString();
+		return "ExpressionEvaluatingSelector for: [" + this.expressionString + "]";
 	}
 
 }
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 2abdc45d5bf..deb4efe3ea0 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
@@ -95,7 +95,13 @@ public void setChannels(List channels) {
 	 */
 	public void setRecipients(List recipients) {
 		Assert.notEmpty(recipients, "recipients must not be empty");
+		ConcurrentLinkedQueue originalRecipients = this.recipients;
+		this.recipients.clear();
 		this.recipients.addAll(recipients);
+		if (logger.isDebugEnabled()) {
+			logger.debug("Channel Recipients:" + originalRecipients
+					+ " replaced with:" + this.recipients);
+		}
 	}
 
 	/**
@@ -106,6 +112,7 @@ public void setRecipients(List recipients) {
 	@ManagedAttribute
 	public void setRecipientMappings(Map recipientMappings) {
 		Assert.notEmpty(recipientMappings, "recipientMappings must not be empty");
+		ConcurrentLinkedQueue originalRecipients = this.recipients;
 		this.recipients.clear();
 		for(Iterator> it = recipientMappings.entrySet().iterator(); it.hasNext();) {
 			Entry next = it.next();
@@ -115,7 +122,10 @@ public void setRecipientMappings(Map recipientMappings) {
 			else {
 				this.addRecipient(next.getKey());
 			}
-
+		}
+		if (logger.isDebugEnabled()) {
+			logger.debug("Channel Recipients:" + originalRecipients
+					+ " replaced with:" + this.recipients);
 		}
 	}
 
@@ -201,6 +211,7 @@ public Collection getRecipients() {
 	public void replaceRecipients(Properties recipientMappings) {
 		Assert.notNull(recipientMappings, "'recipientMappings' must not be null");
 		Set keys = recipientMappings.stringPropertyNames();
+		ConcurrentLinkedQueue originalRecipients = this.recipients;
 		this.recipients.clear();
 		for (String key : keys) {
 			Assert.notNull(key, "channelName can't be null.");
@@ -211,6 +222,10 @@ public void replaceRecipients(Properties recipientMappings) {
 				this.addRecipient(key);
 			}
 		}
+		if (logger.isDebugEnabled()) {
+			logger.debug("Channel Recipients:" + originalRecipients
+					+ " replaced with:" + this.recipients);
+		}
 	}
 
 

From 0c2e0811aa419d20f274b453b5a1d71793a2a12a Mon Sep 17 00:00:00 2001
From: David Liu 
Date: Sun, 3 Aug 2014 22:09:48 +0800
Subject: [PATCH 10/15] INT-2856: allow recipient channel null on init

---
 .../config/xml/RecipientListRouterParser.java        |  7 +++----
 .../integration/router/RecipientListRouter.java      |  9 +++++----
 .../config/xml/spring-integration-4.1.xsd            |  4 ++--
 .../ControlBusRecipientListRouterTests-context.xml   |  4 +---
 .../xml/ControlBusRecipientListRouterTests.java      | 12 ++++--------
 .../integration/router/RecipientListRouterTests.java |  5 ++++-
 6 files changed, 19 insertions(+), 22 deletions(-)

diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/RecipientListRouterParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/RecipientListRouterParser.java
index f4aedd4bd4a..2c430d6ee59 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/RecipientListRouterParser.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/RecipientListRouterParser.java
@@ -28,7 +28,6 @@
 import org.springframework.integration.filter.ExpressionEvaluatingSelector;
 import org.springframework.integration.router.RecipientListRouter;
 import org.springframework.integration.router.RecipientListRouter.Recipient;
-import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
 import org.springframework.util.xml.DomUtils;
 
@@ -47,8 +46,6 @@ public class RecipientListRouterParser extends AbstractRouterParser {
 	protected BeanDefinition doParseRouter(Element element, ParserContext parserContext) {
 		BeanDefinitionBuilder recipientListRouterBuilder = BeanDefinitionBuilder.genericBeanDefinition(RecipientListRouter.class);
 		List childElements = DomUtils.getChildElementsByTagName(element, "recipient");
-		Assert.notEmpty(childElements,
-				"At least one recipient channel must be defined (e.g., ).");
 		ManagedList recipientList = new ManagedList();
 		for (Element childElement : childElements) {
 			BeanDefinitionBuilder recipientBuilder = BeanDefinitionBuilder.genericBeanDefinition(Recipient.class);
@@ -62,7 +59,9 @@ protected BeanDefinition doParseRouter(Element element, ParserContext parserCont
 			}
 			recipientList.add(recipientBuilder.getBeanDefinition());
 		}
-		recipientListRouterBuilder.addPropertyValue("recipients", recipientList);
+		if(recipientList.size() > 0) {
+			recipientListRouterBuilder.addPropertyValue("recipients", recipientList);
+		}
 		return recipientListRouterBuilder.getBeanDefinition();
 	}
 
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 deb4efe3ea0..fb825671dc8 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
@@ -136,7 +136,6 @@ public String getComponentType() {
 
 	@Override
 	public void onInit() throws Exception {
-		Assert.notEmpty(this.recipients, "recipient list must not be empty");
 		super.onInit();
 	}
 
@@ -173,8 +172,9 @@ public void addRecipient(String channelName) {
 	@ManagedOperation
 	public int removeRecipient(String channelName) {
 		int counter = 0;
+		MessageChannel channel = this.getBeanFactory().getBean(channelName, MessageChannel.class);
 		for (Iterator it = this.recipients.iterator();it.hasNext();) {
-			if (it.next().getChannel().equals(this.getBeanFactory().getBean(channelName))) {
+			if (it.next().getChannel().equals(channel)) {
 				it.remove();
 				counter++;
 			}
@@ -186,13 +186,14 @@ public int removeRecipient(String channelName) {
 	@ManagedOperation
 	public int removeRecipient(String channelName, String selectorExpression) {
 		int counter = 0;
+		MessageChannel targetChannel = this.getBeanFactory().getBean(channelName, MessageChannel.class);
 		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(this.getBeanFactory().getBean(channelName)) &&
-					((ExpressionEvaluatingSelector)selector).getExpressionString().equals(selectorExpression)) {
+					channel.equals(targetChannel) &&
+					((ExpressionEvaluatingSelector) selector).getExpressionString().equals(selectorExpression)) {
 				it.remove();
 				counter++;
 			}
diff --git a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-4.1.xsd b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-4.1.xsd
index 73f8e537c38..51b52e9d767 100644
--- a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-4.1.xsd
+++ b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-4.1.xsd
@@ -2923,7 +2923,7 @@
             
                 
                     
-                    
+                    
 						
 						    
 						        An expression to be evaluated to determine if this recipient
@@ -2944,7 +2944,7 @@
         
             
                 
-                    
+                    
                         
 						    
 						        An expression to be evaluated to determine if this recipient
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml
index c87e1522dcc..3d5df0f9e59 100644
--- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml
+++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml
@@ -12,9 +12,7 @@
 
 	
 
-	
-		
-	
+	
 	
 	
 		
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java
index 26a9a856c1a..4b1523b20e4 100644
--- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java
+++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java
@@ -77,9 +77,7 @@ public void testAddRecipient() {
 		messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.addRecipient('channel2','true')");
 		Message  message = new GenericMessage(1);
 		channel.send(message);
-		PollableChannel chanel1 = (PollableChannel) context.getBean("channel1");
 		PollableChannel chanel2 = (PollableChannel) context.getBean("channel2");
-		assertTrue(chanel1.receive(0).getPayload().equals(1));
 		assertTrue(chanel2.receive(0).getPayload().equals(1));
 	}
 
@@ -91,9 +89,7 @@ public void testAddRecipientWithNullExpression() {
 
 		Message  message = new GenericMessage(1);
 		channel.send(message);
-		PollableChannel chanel1 = (PollableChannel) context.getBean("channel1");
 		PollableChannel chanel3 = (PollableChannel) context.getBean("channel3");
-		assertTrue(chanel1.receive(0).getPayload().equals(1));
 		assertTrue(chanel3.receive(0).getPayload().equals(1));
 	}
 
@@ -101,6 +97,7 @@ public void testAddRecipientWithNullExpression() {
 	public void testRemoveRecipient() {
 		MessagingTemplate messagingTemplate = new MessagingTemplate();
 		messagingTemplate.setReceiveTimeout(1000);
+		messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.addRecipient('channel1')");
 		messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.addRecipient('channel4')");
 		messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.removeRecipient('channel4')");
 
@@ -116,6 +113,7 @@ public void testRemoveRecipient() {
 	public void testRemoveRecipientWithNullExpression() {
 		MessagingTemplate messagingTemplate = new MessagingTemplate();
 		messagingTemplate.setReceiveTimeout(1000);
+		messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.addRecipient('channel1','true')");
 		messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.addRecipient('channel5','true')");
 		messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.removeRecipient('channel5','true')");
 
@@ -131,7 +129,9 @@ public void testRemoveRecipientWithNullExpression() {
 	public void testGetRecipients() {
 		MessagingTemplate messagingTemplate = new MessagingTemplate();
 		messagingTemplate.setReceiveTimeout(1000);
+		messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.addRecipient('channel1')");
 		messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.getRecipients()");
+		PollableChannel chanel1 = (PollableChannel) context.getBean("channel1");
 		Message result = this.output.receive(0);
 		Collection mappings = (Collection) result.getPayload();
 		assertEquals(context.getBean("channel1"), mappings.iterator().next().getChannel());
@@ -147,9 +147,7 @@ public void testSetRecipients() {
 		this.input.send(message);
 		message = new GenericMessage(1);
 		channel.send(message);
-		PollableChannel chanel1 = (PollableChannel) context.getBean("channel1");
 		PollableChannel chanel6 = (PollableChannel) context.getBean("channel6");
-		assertNull(chanel1.receive(0));
 		assertTrue(chanel6.receive(0).getPayload().equals(1));
 	}
 
@@ -163,9 +161,7 @@ public void testReplaceRecipients() {
 		messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.replaceRecipients('channel7=true')");
 		Message  message = new GenericMessage(1);
 		channel.send(message);
-		PollableChannel chanel1 = (PollableChannel) context.getBean("channel1");
 		PollableChannel chanel7 = (PollableChannel) context.getBean("channel7");
-		assertNull(chanel1.receive(0));
 		assertTrue(chanel7.receive(0).getPayload().equals(1));
 	}
 }
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/router/RecipientListRouterTests.java b/spring-integration-core/src/test/java/org/springframework/integration/router/RecipientListRouterTests.java
index ad88e2b62af..f02a3835996 100644
--- a/spring-integration-core/src/test/java/org/springframework/integration/router/RecipientListRouterTests.java
+++ b/spring-integration-core/src/test/java/org/springframework/integration/router/RecipientListRouterTests.java
@@ -360,7 +360,10 @@ public void emptyChannelListRejected() {
 		router.setChannels(channels);
 	}
 
-	@Test(expected = IllegalArgumentException.class)
+	/*
+	 * RecipientListRouter can have no channel recipient now
+	 */
+//	@Test(expected = IllegalArgumentException.class)
 	public void noChannelListFailsInitialization() {
 		RecipientListRouter router = new RecipientListRouter();
 		router.setBeanFactory(mock(BeanFactory.class));

From 0c8e5ff71013a716d4dc00b878d4f3ca8999065d Mon Sep 17 00:00:00 2001
From: David Liu 
Date: Mon, 4 Aug 2014 06:38:23 +0800
Subject: [PATCH 11/15] INT-2856: chnage equals to == and add test

---
 .../integration/router/RecipientListRouter.java             | 4 ++--
 .../config/xml/ControlBusRecipientListRouterTests.java      | 2 +-
 .../integration/router/RecipientListRouterTests.java        | 6 ++----
 3 files changed, 5 insertions(+), 7 deletions(-)

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 fb825671dc8..7e5978fa939 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
@@ -174,7 +174,7 @@ public int removeRecipient(String channelName) {
 		int counter = 0;
 		MessageChannel channel = this.getBeanFactory().getBean(channelName, MessageChannel.class);
 		for (Iterator it = this.recipients.iterator();it.hasNext();) {
-			if (it.next().getChannel().equals(channel)) {
+			if (it.next().getChannel() == channel) {
 				it.remove();
 				counter++;
 			}
@@ -192,7 +192,7 @@ public int removeRecipient(String channelName, String selectorExpression) {
 			MessageSelector selector = next.getSelector();
 			MessageChannel channel = next.getChannel();
 			if(selector instanceof ExpressionEvaluatingSelector &&
-					channel.equals(targetChannel) &&
+					channel == targetChannel &&
 					((ExpressionEvaluatingSelector) selector).getExpressionString().equals(selectorExpression)) {
 				it.remove();
 				counter++;
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java
index 4b1523b20e4..4f552c4b957 100644
--- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java
+++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests.java
@@ -110,7 +110,7 @@ public void testRemoveRecipient() {
 	}
 
 	@Test
-	public void testRemoveRecipientWithNullExpression() {
+	public void testRemoveRecipientWithExpression() {
 		MessagingTemplate messagingTemplate = new MessagingTemplate();
 		messagingTemplate.setReceiveTimeout(1000);
 		messagingTemplate.convertAndSend(input, "@'simpleRouter.handler'.addRecipient('channel1','true')");
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/router/RecipientListRouterTests.java b/spring-integration-core/src/test/java/org/springframework/integration/router/RecipientListRouterTests.java
index f02a3835996..bbec6c3c74e 100644
--- a/spring-integration-core/src/test/java/org/springframework/integration/router/RecipientListRouterTests.java
+++ b/spring-integration-core/src/test/java/org/springframework/integration/router/RecipientListRouterTests.java
@@ -360,14 +360,12 @@ public void emptyChannelListRejected() {
 		router.setChannels(channels);
 	}
 
-	/*
-	 * RecipientListRouter can have no channel recipient now
-	 */
-//	@Test(expected = IllegalArgumentException.class)
+	@Test
 	public void noChannelListFailsInitialization() {
 		RecipientListRouter router = new RecipientListRouter();
 		router.setBeanFactory(mock(BeanFactory.class));
 		router.afterPropertiesSet();
+		assertNotNull(router);
 	}
 
 	@Test

From aabe05810d811f09905545d5ce4508159fc1ea04 Mon Sep 17 00:00:00 2001
From: David Liu 
Date: Mon, 4 Aug 2014 15:52:40 +0800
Subject: [PATCH 12/15] INT-2856: add doc

---
 src/reference/docbook/router.xml    | 5 +++++
 src/reference/docbook/whats-new.xml | 9 +++++++++
 2 files changed, 14 insertions(+)

diff --git a/src/reference/docbook/router.xml b/src/reference/docbook/router.xml
index a8f8acee349..34dced2732d 100644
--- a/src/reference/docbook/router.xml
+++ b/src/reference/docbook/router.xml
@@ -557,6 +557,11 @@
              should be included in the recipient list for a given input Message. The evaluation result of the expression must be a boolean. If this
              attribute is not defined, the channel will always be among the list of recipients.
           
+          
+			The RecipientListRouter support following ManagedOperation:
+				addRecipient, removeRecipient, replaceRecipients and
+				following ManagedAttribute: getRecipients, setRecipientMappings 
+			
       
 
       
diff --git a/src/reference/docbook/whats-new.xml b/src/reference/docbook/whats-new.xml index b96ba11e6f6..038181568e9 100644 --- a/src/reference/docbook/whats-new.xml +++ b/src/reference/docbook/whats-new.xml @@ -74,5 +74,14 @@ See for more information.
+
+ Add ManagedOperation and ManagedAttribute in RecipientListRouter + + The RecipientListRouter will support following ManagedOperation: + addRecipient, removeRecipient, replaceRecipients and + following ManagedAttribute: getRecipients, setRecipientMappings + See for more information. + +
From 47f31156794002a12579329f3a445ae2d4fd3af5 Mon Sep 17 00:00:00 2001 From: David Liu Date: Mon, 4 Aug 2014 22:43:19 +0800 Subject: [PATCH 13/15] INT-2856: revise doc --- src/reference/docbook/router.xml | 27 ++++++++++++++++++++++----- src/reference/docbook/whats-new.xml | 7 +++---- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/reference/docbook/router.xml b/src/reference/docbook/router.xml index 34dced2732d..4a2c252dca9 100644 --- a/src/reference/docbook/router.xml +++ b/src/reference/docbook/router.xml @@ -557,12 +557,29 @@ should be included in the recipient list for a given input Message. The evaluation result of the expression must be a boolean. If this attribute is not defined, the channel will always be among the list of recipients. - - The RecipientListRouter support following ManagedOperation: - addRecipient, removeRecipient, replaceRecipients and - following ManagedAttribute: getRecipients, setRecipientMappings - + +
+ RecipientListRouterManagement + + Starting with version 4.1, a RecipientListRouterManagement will support adding and removing + recipients dynamically etc: + + + + + ]]> + + + + <recipient-list-router> can have no <recipient> for feature reconfiguration at runtime + +
XPath Router diff --git a/src/reference/docbook/whats-new.xml b/src/reference/docbook/whats-new.xml index 038181568e9..6c6e81081fd 100644 --- a/src/reference/docbook/whats-new.xml +++ b/src/reference/docbook/whats-new.xml @@ -74,12 +74,11 @@ See for more information.
-
+
Add ManagedOperation and ManagedAttribute in RecipientListRouter - The RecipientListRouter will support following ManagedOperation: - addRecipient, removeRecipient, replaceRecipients and - following ManagedAttribute: getRecipients, setRecipientMappings + The RecipientListRouterManagement implemented by RecipientListRouter + will support ManagedOperation and ManagedAttribute See for more information.
From c6cee1473490f3aa95538e722b1264ea66ba716f Mon Sep 17 00:00:00 2001 From: David Liu Date: Tue, 5 Aug 2014 06:38:26 +0800 Subject: [PATCH 14/15] INT-2856: remove oninit --- .../integration/router/RecipientListRouter.java | 4 ---- 1 file changed, 4 deletions(-) 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 7e5978fa939..32f0c44b959 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 @@ -134,10 +134,6 @@ public String getComponentType() { return "recipient-list-router"; } - @Override - public void onInit() throws Exception { - super.onInit(); - } @Override protected Collection determineTargetChannels(Message message) { From 53affa50135a16b09f8b1f1878f35d3eb3aea25b Mon Sep 17 00:00:00 2001 From: David Liu Date: Tue, 5 Aug 2014 19:51:38 +0800 Subject: [PATCH 15/15] INT-2856 add Assert.notEmpty and format code --- .../integration/router/RecipientListRouter.java | 9 +++++++-- .../router/RecipientListRouterManagement.java | 4 ++-- .../xml/ControlBusRecipientListRouterTests-context.xml | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) 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 32f0c44b959..59670f6216d 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,8 +35,8 @@ import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; -import reactor.util.StringUtils; /** *
@@ -150,6 +150,9 @@ protected Collection determineTargetChannels(Message message)
 	@ManagedOperation
 	public void addRecipient(String channelName, String selectorExpression) {
 		Assert.notNull(channelName, "channelName can't be null.");
+		Assert.hasText(channelName, "channelName can't be empty.");
+		Assert.notNull(selectorExpression, "selectorExpression can't be null.");
+		Assert.hasText(selectorExpression, "selectorExpression can't be empty.");
 		MessageChannel channel = this.getBeanFactory().getBean(channelName, MessageChannel.class);
 		ExpressionEvaluatingSelector expressionEvaluatingSelector = new ExpressionEvaluatingSelector(selectorExpression);
 		expressionEvaluatingSelector.setBeanFactory(this.getBeanFactory());
@@ -169,7 +172,7 @@ public void addRecipient(String channelName) {
 	public int removeRecipient(String channelName) {
 		int counter = 0;
 		MessageChannel channel = this.getBeanFactory().getBean(channelName, MessageChannel.class);
-		for (Iterator it = this.recipients.iterator();it.hasNext();) {
+		for (Iterator it = this.recipients.iterator(); it.hasNext();) {
 			if (it.next().getChannel() == channel) {
 				it.remove();
 				counter++;
@@ -207,6 +210,7 @@ public Collection getRecipients() {
 	@ManagedOperation
 	public void replaceRecipients(Properties recipientMappings) {
 		Assert.notNull(recipientMappings, "'recipientMappings' must not be null");
+		Assert.notEmpty(recipientMappings, "'recipientMappings' must not be empty");
 		Set keys = recipientMappings.stringPropertyNames();
 		ConcurrentLinkedQueue originalRecipients = this.recipients;
 		this.recipients.clear();
@@ -254,4 +258,5 @@ public boolean accept(Message message) {
 			return (this.selector == null || this.selector.accept(message));
 		}
 	}
+
 }
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientListRouterManagement.java b/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientListRouterManagement.java
index a02e371204d..d227c07a1a0 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientListRouterManagement.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/router/RecipientListRouterManagement.java
@@ -38,7 +38,7 @@ public interface RecipientListRouterManagement {
 	/**
 	 * Add a recipient with channelName and expression.
 	 * @param channelName The channel name.
-	 * @param expression The expression to filter the incoming message.
+	 * @param selectorExpression The expression to filter the incoming message.
 	 */
 	@ManagedOperation
 	void addRecipient(String channelName, String selectorExpression);
@@ -60,7 +60,7 @@ public interface RecipientListRouterManagement {
 	/**
 	 * Remove all recipients that match the channelName and expression.
 	 * @param channelName The channel name.
-	 * @param expression The expression to filter the incoming message
+	 * @param selectorExpression The expression to filter the incoming message
 	 */
 	@ManagedOperation
 	int removeRecipient(String channelName, String selectorExpression);
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml
index 3d5df0f9e59..18694a6ca04 100644
--- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml
+++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ControlBusRecipientListRouterTests-context.xml
@@ -1,6 +1,6 @@