ChannelMapping is now ChannelResolver, the BeanNameChannelResolver implementation is now BeanFactoryChannelResolver, and the AbstractChannelMappingMessageRouter base class is now AbstractChannelNameResolvingMessageRouter. The naming is primarily intended to be consistent with DestinationResolver in Spring's JMS support with the ChannelResolver's method name being 'resolveChannelName()' and its return value being a MessageChannel instance. Also, added a ChannelResolutionException.

This commit is contained in:
Mark Fisher
2008-10-12 17:15:29 +00:00
parent 5c5b414cc4
commit 0754889c5c
17 changed files with 312 additions and 240 deletions

View File

@@ -0,0 +1,46 @@
/*
* 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.channel;
import org.springframework.integration.message.MessagingException;
/**
* Thrown by a ChannelResolver when it cannot resolve a channel name.
*
* @author Mark Fisher
* @see ChannelResolver
*/
public class ChannelResolutionException extends MessagingException {
/**
* Create a new ChannelResolutionException.
* @param description the description
*/
public ChannelResolutionException(String description) {
super(description);
}
/**
* Create a new ChannelResolutionException.
* @param description the description
* @param cause the root cause (if any)
*/
public ChannelResolutionException(String description, Throwable cause) {
super(description, cause);
}
}

View File

@@ -22,7 +22,7 @@ import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.integration.annotation.Router;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.message.MessageConsumer;
import org.springframework.integration.router.BeanNameChannelMapping;
import org.springframework.integration.router.BeanFactoryChannelResolver;
import org.springframework.integration.router.MethodInvokingRouter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -42,7 +42,7 @@ public class RouterAnnotationPostProcessor extends AbstractMethodAnnotationPostP
@Override
protected MessageConsumer createConsumer(Object bean, Method method, Router annotation) {
MethodInvokingRouter router = new MethodInvokingRouter(bean, method);
router.setChannelMapping(new BeanNameChannelMapping(this.beanFactoryAccessor.getBeanFactory()));
router.setChannelResolver(new BeanFactoryChannelResolver(this.beanFactoryAccessor.getBeanFactory()));
String defaultOutputChannelName = annotation.defaultOutputChannel();
if (StringUtils.hasText(defaultOutputChannelName)) {
MessageChannel defaultOutputChannel = this.channelRegistry.lookupChannel(defaultOutputChannelName);

View File

@@ -21,7 +21,7 @@ import org.w3c.dom.Element;
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.router.BeanNameChannelMapping;
import org.springframework.integration.router.BeanFactoryChannelResolver;
import org.springframework.integration.router.MethodInvokingRouter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -43,11 +43,10 @@ public class RouterParser extends AbstractConsumerEndpointParser {
String method = element.getAttribute(METHOD_ATTRIBUTE);
builder.addConstructorArgValue(method);
}
BeanDefinitionBuilder channelMappingBuilder =
BeanDefinitionBuilder.genericBeanDefinition(BeanNameChannelMapping.class);
String channelMappingBeanName = BeanDefinitionReaderUtils.registerWithGeneratedName(
channelMappingBuilder.getBeanDefinition(), parserContext.getRegistry());
builder.addPropertyReference("channelMapping", channelMappingBeanName);
BeanDefinitionBuilder resolverBuilder = BeanDefinitionBuilder.genericBeanDefinition(BeanFactoryChannelResolver.class);
String resolverBeanName = BeanDefinitionReaderUtils.registerWithGeneratedName(
resolverBuilder.getBeanDefinition(), parserContext.getRegistry());
builder.addPropertyReference("channelResolver", resolverBeanName);
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "default-output-channel");
return builder;
}

View File

@@ -33,9 +33,9 @@ import org.springframework.util.Assert;
*
* @author Mark Fisher
*/
public abstract class AbstractChannelMappingMessageRouter extends AbstractMessageRouter implements BeanFactoryAware, InitializingBean {
public abstract class AbstractChannelNameResolvingMessageRouter extends AbstractMessageRouter implements BeanFactoryAware, InitializingBean {
private volatile ChannelMapping channelMapping;
private volatile ChannelResolver channelResolver;
private volatile String prefix;
@@ -44,8 +44,8 @@ public abstract class AbstractChannelMappingMessageRouter extends AbstractMessag
private volatile BeanFactory beanFactory;
public void setChannelMapping(ChannelMapping channelMapping) {
this.channelMapping = channelMapping;
public void setChannelResolver(ChannelResolver channelResolver) {
this.channelResolver = channelResolver;
}
public void setPrefix(String prefix) {
@@ -61,9 +61,9 @@ public abstract class AbstractChannelMappingMessageRouter extends AbstractMessag
}
public void afterPropertiesSet() {
if (this.channelMapping == null) {
Assert.notNull(beanFactory, "either a ChannelMapping or BeanFactory is required");
this.channelMapping = new BeanNameChannelMapping(this.beanFactory);
if (this.channelResolver == null) {
Assert.notNull(beanFactory, "either a ChannelResolver or BeanFactory is required");
this.channelResolver = new BeanFactoryChannelResolver(this.beanFactory);
}
}
@@ -77,18 +77,18 @@ public abstract class AbstractChannelMappingMessageRouter extends AbstractMessag
}
for (String channelName : channelNames) {
if (channelName != null) {
Assert.state(this.channelMapping != null,
"unable to resolve channels, no ChannelMapping available");
Assert.state(this.channelResolver != null,
"unable to resolve channel names, no ChannelResolver available");
if (this.prefix != null) {
channelName = this.prefix + channelName;
}
if (this.suffix != null) {
channelName = channelName + suffix;
}
MessageChannel channel = this.channelMapping.getChannel(channelName);
MessageChannel channel = this.channelResolver.resolveChannelName(channelName);
if (channel == null) {
throw new MessagingException(message,
"unable to resolve channel '" + channelName + "'");
"failed to resolve channel name '" + channelName + "'");
}
channels.add(channel);
}

View File

@@ -21,7 +21,7 @@ import org.springframework.integration.message.Message;
/**
* @author Mark Fisher
*/
public abstract class AbstractSingleChannelNameRouter extends AbstractChannelMappingMessageRouter {
public abstract class AbstractSingleChannelNameRouter extends AbstractChannelNameResolvingMessageRouter {
@Override
protected final String[] resolveChannelNames(Message<?> message) {

View File

@@ -0,0 +1,81 @@
/*
* 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.router;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.integration.channel.ChannelResolutionException;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.util.Assert;
/**
* {@link ChannelResolver} implementation based on a Spring {@link BeanFactory}.
*
* <p>Will lookup Spring managed beans identified by bean name,
* expecting them to be of type {@link MessageChannel}.
*
* @author Mark Fisher
* @see org.springframework.beans.factory.BeanFactory
*/
public class BeanFactoryChannelResolver implements ChannelResolver, BeanFactoryAware {
private volatile BeanFactory beanFactory;
/**
* Create a new instance of the {@link BeanFactoryChannelResolver} class.
* <p>The BeanFactory to access must be set via <code>setBeanFactory</code>.
* This will happen automatically if this resolver is defined within an
* ApplicationContext thereby receiving the callback.
* @see #setBeanFactory
*/
public BeanFactoryChannelResolver() {
}
/**
* Create a new instance of the {@link BeanFactoryChannelResolver} class.
* <p>Use of this constructor is redundant if this object is being created
* by a Spring IoC container as the supplied {@link BeanFactory} will be
* replaced by the {@link BeanFactory} that creates it (c.f. the
* {@link BeanFactoryAware} contract). So only use this constructor if you
* are instantiating this object explicitly rather than defining a bean.
*
* @param beanFactory the bean factory to be used to lookup {@link MessageChannel}s.
*/
public BeanFactoryChannelResolver(BeanFactory beanFactory) {
Assert.notNull(beanFactory, "BeanFactory must not be null");
this.beanFactory = beanFactory;
}
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public MessageChannel resolveChannelName(String name) {
Assert.state(this.beanFactory != null, "BeanFactory is required");
try {
return (MessageChannel) this.beanFactory.getBean(name, MessageChannel.class);
}
catch (BeansException e) {
throw new ChannelResolutionException(
"failed to look up MessageChannel bean with name '" + name + "'", e);
}
}
}

View File

@@ -1,61 +0,0 @@
/*
* 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.router;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.util.Assert;
/**
* An implementation of the ChannelMapping strategy that retrieves a
* MessageChannel instance from the {@link BeanFactory} using the provided
* name.
*
* @author Mark Fisher
*/
public class BeanNameChannelMapping implements ChannelMapping, BeanFactoryAware {
private volatile BeanFactory beanFactory;
/**
* Constructor for use within a context where the BeanFactory will be
* injected via the {@link #setBeanFactory(BeanFactory)} callback method.
*/
public BeanNameChannelMapping() {
}
/**
* Constructor for programmatic creation from within other components that
* already have access to the {@link BeanFactory}.
*/
public BeanNameChannelMapping(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public MessageChannel getChannel(String name) {
Assert.state(this.beanFactory != null, "beanFactory must not be null");
return (MessageChannel) this.beanFactory.getBean(name, MessageChannel.class);
}
}

View File

@@ -19,12 +19,15 @@ package org.springframework.integration.router;
import org.springframework.integration.channel.MessageChannel;
/**
* Strategy for mapping from a name to a {@link MessageChannel}.
* Strategy for resolving a name to a {@link MessageChannel}.
*
* @author Mark Fisher
*/
public interface ChannelMapping {
public interface ChannelResolver {
MessageChannel getChannel(String name);
/**
* Return the MessageChannel for the given name.
*/
MessageChannel resolveChannelName(String name);
}

View File

@@ -34,7 +34,7 @@ import org.springframework.util.Assert;
* method's return value may be a single MessageChannel instance, a single
* String to be interpreted as a channel name, or a Collection (or Array) of
* either type. If the method returns channel names, then a
* {@link ChannelMapping} is required.
* {@link ChannelResolver} is required.
*
* @author Mark Fisher
*/
@@ -42,7 +42,7 @@ public class MethodInvokingRouter extends AbstractMessageRouter implements Initi
private final MessageMappingMethodInvoker invoker;
private volatile ChannelMapping channelMapping;
private volatile ChannelResolver channelResolver;
public MethodInvokingRouter(Object object, Method method) {
@@ -55,11 +55,11 @@ public class MethodInvokingRouter extends AbstractMessageRouter implements Initi
/**
* Provide the ChannelMapping strategy to use for methods that return a
* channel name rather than a {@link MessageChannel} instance.
* Provide the {@link ChannelResolver} strategy to use for methods that
* return a channel name rather than a {@link MessageChannel} instance.
*/
public void setChannelMapping(ChannelMapping channelMapping) {
this.channelMapping = channelMapping;
public void setChannelResolver(ChannelResolver channelResolver) {
this.channelResolver = channelResolver;
}
public void afterPropertiesSet() throws Exception {
@@ -108,11 +108,11 @@ public class MethodInvokingRouter extends AbstractMessageRouter implements Initi
}
else if (channelOrName instanceof String) {
String channelName = (String) channelOrName;
Assert.state(this.channelMapping != null,
"ChannelMapping is required for resolving channel names");
MessageChannel channel = this.channelMapping.getChannel(channelName);
Assert.state(this.channelResolver != null,
"unable to resolve channel names, no ChannelResolver available");
MessageChannel channel = this.channelResolver.resolveChannelName(channelName);
if (channel == null) {
throw new MessagingException("unable to resolve channel '" + channelName + "'");
throw new MessagingException("failed to resolve channel name '" + channelName + "'");
}
channels.add(channel);
}

View File

@@ -28,7 +28,7 @@ import org.springframework.util.Assert;
* A Message Router that sends Messages to a statically configured list of
* recipients. The recipients are provided as a list of {@link MessageChannel}
* instances. For dynamic recipient lists, consider instead using the @Router
* annotation or extending {@link AbstractChannelMappingMessageRouter}.
* annotation or extending {@link AbstractChannelNameResolvingMessageRouter}.
*
* @author Mark Fisher
*/