Added RouterFactoryBean. MethodInvokingRouter now provides a constructor to accept the 'targetObject' only (without a method or methodName). It will resolve a single method annotated with @Router or else fallback to a single public method (INT-433, INT-434).
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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;
|
||||
|
||||
import org.springframework.integration.channel.ChannelResolver;
|
||||
import org.springframework.integration.core.MessageChannel;
|
||||
import org.springframework.integration.message.MessageConsumer;
|
||||
import org.springframework.integration.router.AbstractMessageRouter;
|
||||
import org.springframework.integration.router.MethodInvokingRouter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Factory bean for creating a Message Router.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class RouterFactoryBean extends AbstractConsumerFactoryBean {
|
||||
|
||||
private volatile ChannelResolver channelResolver;
|
||||
|
||||
private volatile MessageChannel defaultOutputChannel;
|
||||
|
||||
|
||||
public void setChannelResolver(ChannelResolver channelResolver) {
|
||||
this.channelResolver = channelResolver;
|
||||
}
|
||||
|
||||
public void setDefaultOutputChannel(MessageChannel defaultOutputChannel) {
|
||||
this.defaultOutputChannel = defaultOutputChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MessageConsumer createConsumer(Object targetObject, String targetMethodName) {
|
||||
Assert.notNull(targetObject, "target object must not be null");
|
||||
AbstractMessageRouter router = this.createRouter(targetObject, targetMethodName);
|
||||
if (this.defaultOutputChannel != null) {
|
||||
router.setDefaultOutputChannel(this.defaultOutputChannel);
|
||||
}
|
||||
return router;
|
||||
}
|
||||
|
||||
private AbstractMessageRouter createRouter(Object targetObject, String targetMethodName) {
|
||||
if (targetObject instanceof AbstractMessageRouter) {
|
||||
Assert.isTrue(!StringUtils.hasText(targetMethodName),
|
||||
"target method should not be provided when the target " +
|
||||
"object is an implementation of AbstractMessageRouter");
|
||||
return (AbstractMessageRouter) targetObject;
|
||||
}
|
||||
MethodInvokingRouter router = (StringUtils.hasText(targetMethodName))
|
||||
? new MethodInvokingRouter(targetObject, targetMethodName)
|
||||
: new MethodInvokingRouter(targetObject);
|
||||
if (this.channelResolver != null) {
|
||||
router.setChannelResolver(this.channelResolver);
|
||||
}
|
||||
return router;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.channel.BeanFactoryChannelResolver;
|
||||
import org.springframework.integration.router.MethodInvokingRouter;
|
||||
import org.springframework.integration.config.RouterFactoryBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -37,11 +37,11 @@ public class RouterParser extends AbstractConsumerEndpointParser {
|
||||
protected BeanDefinitionBuilder parseConsumer(Element element, ParserContext parserContext) {
|
||||
String ref = element.getAttribute(REF_ATTRIBUTE);
|
||||
Assert.hasText(ref, "The '" + REF_ATTRIBUTE + "' attribute is required.");
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MethodInvokingRouter.class);
|
||||
builder.addConstructorArgReference(ref);
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(RouterFactoryBean.class);
|
||||
builder.addPropertyReference("targetObject", ref);
|
||||
if (StringUtils.hasText(element.getAttribute(METHOD_ATTRIBUTE))) {
|
||||
String method = element.getAttribute(METHOD_ATTRIBUTE);
|
||||
builder.addConstructorArgValue(method);
|
||||
builder.addPropertyValue("targetMethodName", method);
|
||||
}
|
||||
BeanDefinitionBuilder resolverBuilder = BeanDefinitionBuilder.genericBeanDefinition(BeanFactoryChannelResolver.class);
|
||||
String resolverBeanName = BeanDefinitionReaderUtils.registerWithGeneratedName(
|
||||
|
||||
@@ -23,11 +23,14 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.integration.annotation.Router;
|
||||
import org.springframework.integration.channel.ChannelResolver;
|
||||
import org.springframework.integration.core.Message;
|
||||
import org.springframework.integration.core.MessageChannel;
|
||||
import org.springframework.integration.core.MessagingException;
|
||||
import org.springframework.integration.message.MessageMappingMethodInvoker;
|
||||
import org.springframework.integration.util.DefaultMethodResolver;
|
||||
import org.springframework.integration.util.MethodResolver;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -41,6 +44,8 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class MethodInvokingRouter extends AbstractMessageRouter implements InitializingBean {
|
||||
|
||||
private final MethodResolver methodResolver = new DefaultMethodResolver(Router.class);
|
||||
|
||||
private final MessageMappingMethodInvoker invoker;
|
||||
|
||||
private volatile ChannelResolver channelResolver;
|
||||
@@ -54,6 +59,14 @@ public class MethodInvokingRouter extends AbstractMessageRouter implements Initi
|
||||
this.invoker = new MessageMappingMethodInvoker(object, methodName);
|
||||
}
|
||||
|
||||
public MethodInvokingRouter(Object object) {
|
||||
Assert.notNull(object, "object must not be null");
|
||||
Method method = this.methodResolver.findMethod(object);
|
||||
Assert.notNull(method, "unable to resolve Router method on target class ["
|
||||
+ object.getClass() + "]");
|
||||
this.invoker = new MessageMappingMethodInvoker(object, method);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Provide the {@link ChannelResolver} strategy to use for methods that
|
||||
|
||||
@@ -17,15 +17,21 @@
|
||||
package org.springframework.integration.router.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.integration.annotation.Router;
|
||||
import org.springframework.integration.channel.PollableChannel;
|
||||
import org.springframework.integration.core.Message;
|
||||
import org.springframework.integration.core.MessageChannel;
|
||||
import org.springframework.integration.message.StringMessage;
|
||||
import org.springframework.integration.router.AbstractMessageRouter;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
@@ -66,4 +72,60 @@ public class RouterParserTests {
|
||||
assertEquals("99", result.getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refOnlyForAbstractMessageRouterImplementation() {
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"routerParserTests.xml", this.getClass());
|
||||
context.start();
|
||||
MessageChannel input = (MessageChannel) context.getBean("inputForAbstractMessageRouterImplementation");
|
||||
PollableChannel output = (PollableChannel) context.getBean("output3");
|
||||
input.send(new StringMessage("test-implementation"));
|
||||
Message<?> result = output.receive(0);
|
||||
assertNotNull(result);
|
||||
assertEquals("test-implementation", result.getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refOnlyForAnnotatedObject() {
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"routerParserTests.xml", this.getClass());
|
||||
context.start();
|
||||
MessageChannel input = (MessageChannel) context.getBean("inputForAnnotatedRouter");
|
||||
PollableChannel output = (PollableChannel) context.getBean("output4");
|
||||
input.send(new StringMessage("test-annotation"));
|
||||
Message<?> result = output.receive(0);
|
||||
assertNotNull(result);
|
||||
assertEquals("test-annotation", result.getPayload());
|
||||
}
|
||||
|
||||
|
||||
public static class TestRouterImplementation extends AbstractMessageRouter {
|
||||
|
||||
private final MessageChannel channel;
|
||||
|
||||
public TestRouterImplementation(MessageChannel channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<MessageChannel> determineTargetChannels(Message<?> message) {
|
||||
return Collections.singletonList(this.channel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class AnnotatedTestRouterBean {
|
||||
|
||||
private final MessageChannel channel;
|
||||
|
||||
public AnnotatedTestRouterBean(MessageChannel channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
@Router
|
||||
public MessageChannel test(String payload) {
|
||||
return this.channel;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,4 +33,28 @@
|
||||
|
||||
<beans:bean id="pojo" class="org.springframework.integration.router.config.TestRouter"/>
|
||||
|
||||
<channel id="output3">
|
||||
<queue capacity="1"/>
|
||||
</channel>
|
||||
|
||||
<channel id="inputForAbstractMessageRouterImplementation"/>
|
||||
|
||||
<router input-channel="inputForAbstractMessageRouterImplementation" ref="implementation"/>
|
||||
|
||||
<beans:bean id="implementation" class="org.springframework.integration.router.config.RouterParserTests$TestRouterImplementation">
|
||||
<beans:constructor-arg ref="output3"/>
|
||||
</beans:bean>
|
||||
|
||||
<channel id="output4">
|
||||
<queue capacity="1"/>
|
||||
</channel>
|
||||
|
||||
<channel id="inputForAnnotatedRouter"/>
|
||||
|
||||
<router input-channel="inputForAnnotatedRouter" ref="annotated"/>
|
||||
|
||||
<beans:bean id="annotated" class="org.springframework.integration.router.config.RouterParserTests$AnnotatedTestRouterBean">
|
||||
<beans:constructor-arg ref="output4"/>
|
||||
</beans:bean>
|
||||
|
||||
</beans:beans>
|
||||
|
||||
Reference in New Issue
Block a user