Skip to content

Commit

Permalink
INT-2434-v3 polished based on @garyrussell last comments
Browse files Browse the repository at this point in the history
  • Loading branch information
olegz committed Mar 30, 2012
1 parent 6e34aaa commit 282edb3
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 56 deletions.
Expand Up @@ -16,13 +16,13 @@


package org.springframework.integration.config.xml; package org.springframework.integration.config.xml;


import java.util.HashSet; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Set;


import org.w3c.dom.Element; import org.w3c.dom.Element;


import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionBuilder;
Expand Down Expand Up @@ -93,14 +93,12 @@ protected final AbstractBeanDefinition parseInternal(Element element, ParserCont


if (!parserContext.getRegistry().containsBeanDefinition(inputChannelName)){ if (!parserContext.getRegistry().containsBeanDefinition(inputChannelName)){
BeanDefinition channelRegistry = parserContext.getRegistry().getBeanDefinition(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME); BeanDefinition channelRegistry = parserContext.getRegistry().getBeanDefinition(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);

ConstructorArgumentValues caValues = channelRegistry.getConstructorArgumentValues();
@SuppressWarnings("unchecked") if (caValues != null){

This comment has been minimized.

Copy link
@garyrussell

garyrussell Mar 30, 2012

Should never happen, but I wonder if we should log rather than just silently ignore?

This comment has been minimized.

Copy link
@olegz

olegz Mar 30, 2012

Author Owner

well giving the fact that "should never happen" i say throw exception instead of log. I mean if somehow its null this would be a major mishap, dont you think?

This comment has been minimized.

Copy link
@garyrussell

garyrussell Mar 30, 2012

Exception? or parserContext.getReaderContext().error(...) ??

A log would just say 'auto channel creation disabled', but I think an error is better.

This comment has been minimized.

Copy link
@olegz

olegz via email Mar 30, 2012

Author Owner

This comment has been minimized.

Copy link
@olegz

olegz via email Mar 30, 2012

Author Owner
Set<String> channelNames = (Set<String>) channelRegistry.getAttribute(ChannelInitializer.CHANNEL_NAMES_ATTR); @SuppressWarnings("unchecked")
if (channelNames == null){ Collection<String> channelCandidateNames = (Collection<String>) caValues.getArgumentValue(0, Collection.class).getValue();
channelNames = (Set<String>) new HashSet<String>(); channelCandidateNames.add(inputChannelName);
channelRegistry.setAttribute(ChannelInitializer.CHANNEL_NAMES_ATTR, channelNames);
} }
channelNames.add(inputChannelName);
} }


builder.addPropertyValue("inputChannelName", inputChannelName); builder.addPropertyValue("inputChannelName", inputChannelName);
Expand Down
Expand Up @@ -22,9 +22,9 @@
import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.ManagedSet;
import org.springframework.beans.factory.xml.BeanDefinitionDecorator; import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.NamespaceHandler; import org.springframework.beans.factory.xml.NamespaceHandler;
Expand Down Expand Up @@ -68,19 +68,17 @@ public final BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder def
} }


/* /*
* This method will auto-register ChannelInitializer which could also be overridden by the user * This method will auto-register a ChannelInitializer which could also be overridden by the user
* by simply registering a ChannelInitializer <bean> with 'autoCreate' property set to false. * by simply registering a ChannelInitializer <bean> with its 'autoCreate' property set to false to suppress channel creation.
* It will also register ChannelInitializer$AutoCreateCandidatesCollector which simply collects channelNames to be created. * It will also register a ChannelInitializer$AutoCreateCandidatesCollector which simply collects candidate channel names.
* It does a little more so please read its comments. ChannelInitializer$AutoCreateCandidatesCollector
* can NOT be overridden by the user
*/ */
private void registerImplicitChannelCreator(ParserContext parserContext) { private void registerImplicitChannelCreator(ParserContext parserContext) {
// ChannelInitializer // ChannelInitializer
boolean alreadyRegistered = false; boolean alreadyRegistered = false;
if (parserContext.getRegistry() instanceof ConfigurableListableBeanFactory) { if (parserContext.getRegistry() instanceof ListableBeanFactory) {
// unlike DefaultConfiguringBeanFactoryPostProcessor we need one of these per registry // unlike DefaultConfiguringBeanFactoryPostProcessor we need one of these per registry
// therefore we need to call containsBeanDefinition(..) which does not consider parent registry // therefore we need to call containsBeanDefinition(..) which does not consider parent registry
alreadyRegistered = ((ConfigurableListableBeanFactory) parserContext.getRegistry()).containsBeanDefinition(CHANNEL_INITIALIZER_BEAN_NAME); alreadyRegistered = ((ListableBeanFactory) parserContext.getRegistry()).containsBeanDefinition(CHANNEL_INITIALIZER_BEAN_NAME);
} }
else { else {
alreadyRegistered = parserContext.getRegistry().isBeanNameInUse(CHANNEL_INITIALIZER_BEAN_NAME); alreadyRegistered = parserContext.getRegistry().isBeanNameInUse(CHANNEL_INITIALIZER_BEAN_NAME);
Expand All @@ -92,17 +90,18 @@ private void registerImplicitChannelCreator(ParserContext parserContext) {
} }
// ChannelInitializer$AutoCreateCandidatesCollector // ChannelInitializer$AutoCreateCandidatesCollector
alreadyRegistered = false; alreadyRegistered = false;
if (parserContext.getRegistry() instanceof ConfigurableListableBeanFactory) { if (parserContext.getRegistry() instanceof ListableBeanFactory) {
// unlike DefaultConfiguringBeanFactoryPostProcessor we need one of these per registry // unlike DefaultConfiguringBeanFactoryPostProcessor we need one of these per registry
// therefore we need to call containsBeanDefinition(..) which does not consider parent registry // therefore we need to call containsBeanDefinition(..) which does not consider parent registry
alreadyRegistered = ((ConfigurableListableBeanFactory) parserContext.getRegistry()). alreadyRegistered = ((ListableBeanFactory) parserContext.getRegistry()).
containsBeanDefinition(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME); containsBeanDefinition(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
} }
else { else {
alreadyRegistered = parserContext.getRegistry().isBeanNameInUse(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME); alreadyRegistered = parserContext.getRegistry().isBeanNameInUse(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
} }
if (!alreadyRegistered) { if (!alreadyRegistered) {
BeanDefinitionBuilder channelRegistryBuilder = BeanDefinitionBuilder.genericBeanDefinition(AutoCreateCandidatesCollector.class); BeanDefinitionBuilder channelRegistryBuilder = BeanDefinitionBuilder.genericBeanDefinition(AutoCreateCandidatesCollector.class);
channelRegistryBuilder.addConstructorArgValue(new ManagedSet<String>());
BeanDefinitionHolder channelRegistryHolder = BeanDefinitionHolder channelRegistryHolder =
new BeanDefinitionHolder(channelRegistryBuilder.getBeanDefinition(), ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME); new BeanDefinitionHolder(channelRegistryBuilder.getBeanDefinition(), ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
BeanDefinitionReaderUtils.registerBeanDefinition(channelRegistryHolder, parserContext.getRegistry()); BeanDefinitionReaderUtils.registerBeanDefinition(channelRegistryHolder, parserContext.getRegistry());
Expand Down
Expand Up @@ -24,20 +24,15 @@
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedSet;
import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.integration.channel.DirectChannel; import org.springframework.integration.channel.DirectChannel;


/** /**
* A {@link InitializingBean} implementation that is responsible for creating * A {@link InitializingBean} implementation that is responsible for creating
* channels that are not explicitly defined but identified via 'input-channel' * channels that are not explicitly defined but identified via the 'input-channel'
* attribute of the corresponding endpoints. * attribute of the corresponding endpoints.
* *
* This bean plays a role of pre-instantiator since it is instantiated and * This bean plays a role of pre-instantiator since it is instantiated and
Expand Down Expand Up @@ -90,44 +85,20 @@ public void afterPropertiesSet() throws Exception {
} }
} }
} }

/* /*
* This class serves two purposes * Collects candidate channel names to be auto-created by ChannelInitializer
* 1. A BeanDefinition that collects candidate channel names as its BeanDefinition attributes
* 2. A holder of the resolved (property placeholders and SpEL expressions) channel names to be auto-created by the
* ChannelInitializer.
* Once this bean reaches Factory post processing phase it creates a new definition of itself injecting it with
* the ManagedSet of channelNames property. The ManagedSet will be naturally resolved before it is used by the
* ChannelInitializer. It also unregisters its old definition (since its only value was to provide a place
* to collect candidate channel names) and registers new definition of itself with "to-be resolved" channelNames
* property
*/ */
public static class AutoCreateCandidatesCollector implements BeanFactoryPostProcessor{ static class AutoCreateCandidatesCollector {

private volatile Collection<String> channelNames; private final Collection<String> channelNames;

public void setChannelNames(Collection<String> channelNames) { public AutoCreateCandidatesCollector(Collection<String> channelNames){
this.channelNames = channelNames; this.channelNames = channelNames;
} }


public Collection<String> getChannelNames() { public Collection<String> getChannelNames() {
return channelNames; return channelNames;
} }

@SuppressWarnings("unchecked")
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition definition = beanFactory.getBeanDefinition(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
Collection<String> _channelNames = (Collection<String>) definition.getAttribute(ChannelInitializer.CHANNEL_NAMES_ATTR);
if (_channelNames != null){
((BeanDefinitionRegistry)beanFactory).removeBeanDefinition(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
BeanDefinitionBuilder candidatesBuilder = BeanDefinitionBuilder.genericBeanDefinition(this.getClass().getName());
ManagedSet<String> candidateChannelNamesToBeResolved = new ManagedSet<String>();
candidateChannelNamesToBeResolved.addAll(_channelNames);
candidatesBuilder.addPropertyValue("channelNames", candidateChannelNamesToBeResolved);
BeanDefinitionHolder holder = new BeanDefinitionHolder(candidatesBuilder.getBeanDefinition(),
ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
BeanDefinitionReaderUtils.registerBeanDefinition(holder, (BeanDefinitionRegistry) beanFactory);
}
}
} }
} }

0 comments on commit 282edb3

Please sign in to comment.