From 8e35ba237d02ad7de420a653a96ebb5c6761c2e3 Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Fri, 28 Aug 2009 21:30:02 +0000 Subject: [PATCH] INT-775 Added SpEL-based Message Router and parser support for the "expression" attribute on the element. --- .../integration/config/RouterFactoryBean.java | 6 ++ .../AbstractMessageProcessingRouter.java | 51 +++++++++++ .../router/ExpressionEvaluatingRouter.java | 35 ++++++++ .../router/MethodInvokingRouter.java | 25 ++---- .../config/xml/spring-integration-2.0.xsd | 6 +- .../SpelRouterIntegrationTests-context.xml | 22 +++++ .../config/SpelRouterIntegrationTests.java | 87 +++++++++++++++++++ .../SpelSplitterIntegrationTests-context.xml | 2 +- 8 files changed, 210 insertions(+), 24 deletions(-) create mode 100644 org.springframework.integration/src/main/java/org/springframework/integration/router/AbstractMessageProcessingRouter.java create mode 100644 org.springframework.integration/src/main/java/org/springframework/integration/router/ExpressionEvaluatingRouter.java create mode 100644 org.springframework.integration/src/test/java/org/springframework/integration/router/config/SpelRouterIntegrationTests-context.xml create mode 100644 org.springframework.integration/src/test/java/org/springframework/integration/router/config/SpelRouterIntegrationTests.java diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/config/RouterFactoryBean.java b/org.springframework.integration/src/main/java/org/springframework/integration/config/RouterFactoryBean.java index bd78e5b9b5..9c715f042c 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/config/RouterFactoryBean.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/config/RouterFactoryBean.java @@ -21,6 +21,7 @@ import org.springframework.integration.core.MessageChannel; import org.springframework.integration.message.MessageHandler; import org.springframework.integration.router.AbstractChannelNameResolvingMessageRouter; import org.springframework.integration.router.AbstractMessageRouter; +import org.springframework.integration.router.ExpressionEvaluatingRouter; import org.springframework.integration.router.MethodInvokingRouter; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -86,6 +87,11 @@ public class RouterFactoryBean extends AbstractMessageHandlerFactoryBean { return router; } + @Override + MessageHandler createExpressionEvaluatingHandler(String expression) { + return new ExpressionEvaluatingRouter(expression); + } + private AbstractMessageRouter createRouter(Object targetObject, String targetMethodName) { if (targetObject instanceof AbstractMessageRouter) { Assert.isTrue(!StringUtils.hasText(targetMethodName), diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/router/AbstractMessageProcessingRouter.java b/org.springframework.integration/src/main/java/org/springframework/integration/router/AbstractMessageProcessingRouter.java new file mode 100644 index 0000000000..b799e3891a --- /dev/null +++ b/org.springframework.integration/src/main/java/org/springframework/integration/router/AbstractMessageProcessingRouter.java @@ -0,0 +1,51 @@ +/* + * Copyright 2002-2009 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 java.util.ArrayList; +import java.util.List; + +import org.springframework.integration.core.Message; +import org.springframework.integration.handler.MessageProcessor; +import org.springframework.util.Assert; + +/** + * A base class for Router implementations that delegate to a + * {@link MessageProcessor} instance. + * + * @author Mark Fisher + * @since 2.0 + */ +class AbstractMessageProcessingRouter extends AbstractChannelNameResolvingMessageRouter { + + private final MessageProcessor messageProcessor; + + + AbstractMessageProcessingRouter(MessageProcessor messageProcessor) { + Assert.notNull(messageProcessor, "messageProcessor must not be null"); + this.messageProcessor = messageProcessor; + } + + @Override + protected List getChannelIndicatorList(Message message) { + Object result = this.messageProcessor.processMessage(message); + List asList = new ArrayList(); + asList.add(result); + return asList; + } + +} diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/router/ExpressionEvaluatingRouter.java b/org.springframework.integration/src/main/java/org/springframework/integration/router/ExpressionEvaluatingRouter.java new file mode 100644 index 0000000000..d2021d6b9c --- /dev/null +++ b/org.springframework.integration/src/main/java/org/springframework/integration/router/ExpressionEvaluatingRouter.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2009 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.handler.ExpressionEvaluatingMessageProcessor; + +/** + * A Message Router implementation that evaluates the specified SpEL + * expression. The result of evaluation will typically be a String to be + * resolved to a channel name or a Collection (or Array) of strings. + * + * @author Mark Fisher + * @since 2.0 + */ +public class ExpressionEvaluatingRouter extends AbstractMessageProcessingRouter { + + public ExpressionEvaluatingRouter(String expression) { + super(new ExpressionEvaluatingMessageProcessor(expression)); + } + +} diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/router/MethodInvokingRouter.java b/org.springframework.integration/src/main/java/org/springframework/integration/router/MethodInvokingRouter.java index 94fcd6147d..0c3ea2da1f 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/router/MethodInvokingRouter.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/router/MethodInvokingRouter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2009 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. @@ -17,12 +17,9 @@ package org.springframework.integration.router; import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; import org.springframework.integration.annotation.Router; import org.springframework.integration.channel.ChannelResolver; -import org.springframework.integration.core.Message; import org.springframework.integration.handler.MessageMappingMethodInvoker; /** @@ -34,30 +31,18 @@ import org.springframework.integration.handler.MessageMappingMethodInvoker; * * @author Mark Fisher */ -public class MethodInvokingRouter extends AbstractChannelNameResolvingMessageRouter { - - private final MessageMappingMethodInvoker invoker; - - +public class MethodInvokingRouter extends AbstractMessageProcessingRouter { public MethodInvokingRouter(Object object, Method method) { - this.invoker = new MessageMappingMethodInvoker(object, method); + super(new MessageMappingMethodInvoker(object, method)); } public MethodInvokingRouter(Object object, String methodName) { - this.invoker = new MessageMappingMethodInvoker(object, methodName); + super(new MessageMappingMethodInvoker(object, methodName)); } public MethodInvokingRouter(Object object) { - this.invoker = new MessageMappingMethodInvoker(object, Router.class); - } - - @Override - protected List getChannelIndicatorList(Message message) { - Object result = this.invoker.processMessage(message); - List asList = new ArrayList(); - asList.add(result); - return asList; + super(new MessageMappingMethodInvoker(object, Router.class)); } } diff --git a/org.springframework.integration/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd b/org.springframework.integration/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd index 771490f532..08d1c31283 100644 --- a/org.springframework.integration/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd +++ b/org.springframework.integration/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd @@ -1136,9 +1136,8 @@ - - + + @@ -1150,6 +1149,7 @@ + + + + + + + + + + + + + + + + diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/router/config/SpelRouterIntegrationTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/router/config/SpelRouterIntegrationTests.java new file mode 100644 index 0000000000..201d54a67e --- /dev/null +++ b/org.springframework.integration/src/test/java/org/springframework/integration/router/config/SpelRouterIntegrationTests.java @@ -0,0 +1,87 @@ +/* + * Copyright 2002-2009 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.config; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +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.integration.channel.PollableChannel; +import org.springframework.integration.core.Message; +import org.springframework.integration.core.MessageChannel; +import org.springframework.integration.message.MessageBuilder; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Mark Fisher + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class SpelRouterIntegrationTests { + + @Autowired @Qualifier("input") + private MessageChannel input; + + @Autowired @Qualifier("even") + private PollableChannel even; + + @Autowired @Qualifier("odd") + private PollableChannel odd; + + + @Test + public void split() { + TestBean testBean1 = new TestBean(1); + TestBean testBean2 = new TestBean(2); + TestBean testBean3 = new TestBean(3); + TestBean testBean4 = new TestBean(4); + Message message1 = MessageBuilder.withPayload(testBean1).build(); + Message message2 = MessageBuilder.withPayload(testBean2).build(); + Message message3 = MessageBuilder.withPayload(testBean3).build(); + Message message4 = MessageBuilder.withPayload(testBean4).build(); + this.input.send(message1); + this.input.send(message2); + this.input.send(message3); + this.input.send(message4); + assertEquals(testBean1, odd.receive(0).getPayload()); + assertEquals(testBean2, even.receive(0).getPayload()); + assertEquals(testBean3, odd.receive(0).getPayload()); + assertEquals(testBean4, even.receive(0).getPayload()); + assertNull(odd.receive(0)); + assertNull(even.receive(0)); + } + + + static class TestBean { + + private final int number; + + public TestBean(int number) { + this.number = number; + } + + public int getNumber() { + return this.number; + } + } + +} diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/splitter/SpelSplitterIntegrationTests-context.xml b/org.springframework.integration/src/test/java/org/springframework/integration/splitter/SpelSplitterIntegrationTests-context.xml index f3b830e939..b26ec4f619 100644 --- a/org.springframework.integration/src/test/java/org/springframework/integration/splitter/SpelSplitterIntegrationTests-context.xml +++ b/org.springframework.integration/src/test/java/org/springframework/integration/splitter/SpelSplitterIntegrationTests-context.xml @@ -15,6 +15,6 @@ - +