Merge pull request #360 from olegz/INT-2434-v3
This commit is contained in:
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beansProjectDescription>
|
||||
<version>1</version>
|
||||
<pluginVersion><![CDATA[2.7.1.201107082359-RELEASE]]></pluginVersion>
|
||||
<configSuffixes>
|
||||
<configSuffix><![CDATA[xml]]></configSuffix>
|
||||
</configSuffixes>
|
||||
<enableImports><![CDATA[false]]></enableImports>
|
||||
<configs>
|
||||
<config>src/test/java/org/springframework/integration/gateway/GatewayInterfaceTest-context.xml</config>
|
||||
<config>src/test/java/org/springframework/integration/gateway/InnerGatewayWithChainTests-context.xml</config>
|
||||
<config>src/test/java/org/springframework/integration/history/annotated-config.xml</config>
|
||||
<config>src/test/java/org/springframework/integration/aggregator/config.xml</config>
|
||||
</configs>
|
||||
<configSets>
|
||||
</configSets>
|
||||
</beansProjectDescription>
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -16,19 +16,22 @@
|
||||
|
||||
package org.springframework.integration.config.xml;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.support.ManagedSet;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.integration.config.ConsumerEndpointFactoryBean;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
|
||||
@@ -46,7 +49,6 @@ public abstract class AbstractConsumerEndpointParser extends AbstractBeanDefinit
|
||||
|
||||
protected static final String EXPRESSION_ATTRIBUTE = "expression";
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean shouldGenerateId() {
|
||||
return false;
|
||||
@@ -83,28 +85,34 @@ public abstract class AbstractConsumerEndpointParser extends AbstractBeanDefinit
|
||||
return handlerBeanDefinition;
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
|
||||
IntegrationNamespaceUtils.BASE_PACKAGE + ".config.ConsumerEndpointFactoryBean");
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ConsumerEndpointFactoryBean.class);
|
||||
|
||||
String handlerBeanName = BeanDefinitionReaderUtils.generateBeanName(handlerBeanDefinition, parserContext.getRegistry());
|
||||
parserContext.registerBeanComponent(new BeanComponentDefinition(handlerBeanDefinition, handlerBeanName));
|
||||
|
||||
|
||||
builder.addPropertyReference("handler", handlerBeanName);
|
||||
String inputChannelName = element.getAttribute(inputChannelAttributeName);
|
||||
boolean channelExists = false;
|
||||
if (parserContext.getRegistry() instanceof BeanFactory) {
|
||||
// BeanFactory also checks ancestor contexts in a hierarchy
|
||||
channelExists = ((BeanFactory) parserContext.getRegistry()).containsBean(inputChannelName);
|
||||
}
|
||||
else {
|
||||
channelExists = parserContext.getRegistry().containsBeanDefinition(inputChannelName);
|
||||
}
|
||||
if (!channelExists && this.shouldAutoCreateChannel(inputChannelName)) {
|
||||
BeanDefinitionBuilder channelDef = BeanDefinitionBuilder.genericBeanDefinition(
|
||||
IntegrationNamespaceUtils.BASE_PACKAGE + ".channel.DirectChannel");
|
||||
BeanDefinitionHolder holder = new BeanDefinitionHolder(channelDef.getBeanDefinition(), inputChannelName);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(holder, parserContext.getRegistry());
|
||||
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(inputChannelName)){
|
||||
if (parserContext.getRegistry().containsBeanDefinition(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME)){
|
||||
BeanDefinition channelRegistry = parserContext.getRegistry().
|
||||
getBeanDefinition(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
|
||||
ConstructorArgumentValues caValues = channelRegistry.getConstructorArgumentValues();
|
||||
ValueHolder vh = caValues.getArgumentValue(0, Collection.class);
|
||||
if (vh == null){ //although it should never happen if it does we can fix it
|
||||
caValues.addIndexedArgumentValue(0, new ManagedSet<String>());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<String> channelCandidateNames = (Collection<String>) caValues.getArgumentValue(0, Collection.class).getValue();
|
||||
channelCandidateNames.add(inputChannelName);
|
||||
}
|
||||
else {
|
||||
parserContext.getReaderContext().error("Failed to locate '" +
|
||||
ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME + "'", parserContext.getRegistry());
|
||||
}
|
||||
}
|
||||
|
||||
builder.addPropertyValue("inputChannelName", inputChannelName);
|
||||
List<Element> pollerElementList = DomUtils.getChildElementsByTagName(element, "poller");
|
||||
if (!CollectionUtils.isEmpty(pollerElementList)) {
|
||||
@@ -120,10 +128,4 @@ public abstract class AbstractConsumerEndpointParser extends AbstractBeanDefinit
|
||||
parserContext.registerBeanComponent(new BeanComponentDefinition(beanDefinition, beanName));
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean shouldAutoCreateChannel(String channelName) {
|
||||
return !IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME.equals(channelName)
|
||||
&& !IntegrationContextUtils.NULL_CHANNEL_BEAN_NAME.equals(channelName);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -24,11 +24,13 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
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.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.NamespaceHandler;
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.ChannelInitializer.AutoCreateCandidatesCollector;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -36,11 +38,14 @@ import org.springframework.util.StringUtils;
|
||||
* for configuring default bean definitions.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Oleg Zhurakousky
|
||||
*/
|
||||
public abstract class AbstractIntegrationNamespaceHandler implements NamespaceHandler {
|
||||
|
||||
private static final String VERSION = "2.1";
|
||||
|
||||
public static final String CHANNEL_INITIALIZER_BEAN_NAME = ChannelInitializer.class.getSimpleName();
|
||||
|
||||
private static final String DEFAULT_CONFIGURING_POSTPROCESSOR_SIMPLE_CLASS_NAME =
|
||||
"DefaultConfiguringBeanFactoryPostProcessor";
|
||||
|
||||
@@ -53,6 +58,7 @@ public abstract class AbstractIntegrationNamespaceHandler implements NamespaceHa
|
||||
|
||||
public final BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
this.verifySchemaVersion(element, parserContext);
|
||||
this.registerImplicitChannelCreator(parserContext);
|
||||
this.registerDefaultConfiguringBeanFactoryPostProcessorIfNecessary(parserContext);
|
||||
return this.delegate.parse(element, parserContext);
|
||||
}
|
||||
@@ -61,6 +67,46 @@ public abstract class AbstractIntegrationNamespaceHandler implements NamespaceHa
|
||||
return this.delegate.decorate(source, definition, parserContext);
|
||||
}
|
||||
|
||||
/*
|
||||
* This method will auto-register a ChannelInitializer which could also be overridden by the user
|
||||
* by simply registering a ChannelInitializer <bean> with its 'autoCreate' property set to false to suppress channel creation.
|
||||
* It will also register a ChannelInitializer$AutoCreateCandidatesCollector which simply collects candidate channel names.
|
||||
*/
|
||||
private void registerImplicitChannelCreator(ParserContext parserContext) {
|
||||
// ChannelInitializer
|
||||
boolean alreadyRegistered = false;
|
||||
if (parserContext.getRegistry() instanceof ListableBeanFactory) {
|
||||
// unlike DefaultConfiguringBeanFactoryPostProcessor we need one of these per registry
|
||||
// therefore we need to call containsBeanDefinition(..) which does not consider parent registry
|
||||
alreadyRegistered = ((ListableBeanFactory) parserContext.getRegistry()).containsBeanDefinition(CHANNEL_INITIALIZER_BEAN_NAME);
|
||||
}
|
||||
else {
|
||||
alreadyRegistered = parserContext.getRegistry().isBeanNameInUse(CHANNEL_INITIALIZER_BEAN_NAME);
|
||||
}
|
||||
if (!alreadyRegistered) {
|
||||
BeanDefinitionBuilder channelDef = BeanDefinitionBuilder.genericBeanDefinition(ChannelInitializer.class);
|
||||
BeanDefinitionHolder channelCreatorHolder = new BeanDefinitionHolder(channelDef.getBeanDefinition(), CHANNEL_INITIALIZER_BEAN_NAME);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(channelCreatorHolder, parserContext.getRegistry());
|
||||
}
|
||||
// ChannelInitializer$AutoCreateCandidatesCollector
|
||||
if (parserContext.getRegistry() instanceof ListableBeanFactory) {
|
||||
// unlike DefaultConfiguringBeanFactoryPostProcessor we need one of these per registry
|
||||
// therefore we need to call containsBeanDefinition(..) which does not consider parent registry
|
||||
alreadyRegistered = ((ListableBeanFactory) parserContext.getRegistry()).
|
||||
containsBeanDefinition(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
|
||||
}
|
||||
else {
|
||||
alreadyRegistered = parserContext.getRegistry().isBeanNameInUse(ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
|
||||
}
|
||||
if (!alreadyRegistered) {
|
||||
BeanDefinitionBuilder channelRegistryBuilder = BeanDefinitionBuilder.genericBeanDefinition(AutoCreateCandidatesCollector.class);
|
||||
channelRegistryBuilder.addConstructorArgValue(new ManagedSet<String>());
|
||||
BeanDefinitionHolder channelRegistryHolder =
|
||||
new BeanDefinitionHolder(channelRegistryBuilder.getBeanDefinition(), ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(channelRegistryHolder, parserContext.getRegistry());
|
||||
}
|
||||
}
|
||||
|
||||
private void registerDefaultConfiguringBeanFactoryPostProcessorIfNecessary(ParserContext parserContext) {
|
||||
boolean alreadyRegistered = false;
|
||||
if (parserContext.getRegistry() instanceof ListableBeanFactory) {
|
||||
@@ -125,5 +171,4 @@ public abstract class AbstractIntegrationNamespaceHandler implements NamespaceHa
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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 java.util.Collection;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link InitializingBean} implementation that is responsible for creating
|
||||
* channels that are not explicitly defined but identified via the 'input-channel'
|
||||
* attribute of the corresponding endpoints.
|
||||
*
|
||||
* This bean plays a role of pre-instantiator since it is instantiated and
|
||||
* initialized as the very first bean of all SI beans using
|
||||
* {@link AbstractIntegrationNamespaceHandler}.
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
* @since 2.1.1
|
||||
*/
|
||||
final class ChannelInitializer implements BeanFactoryAware, InitializingBean {
|
||||
|
||||
public static String AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME = "$autoCreateChannelCandidates";
|
||||
public static String CHANNEL_NAMES_ATTR = "channelNames";
|
||||
|
||||
private Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private volatile BeanFactory beanFactory;
|
||||
|
||||
private volatile boolean autoCreate = true;
|
||||
|
||||
public void setAutoCreate(boolean autoCreate) {
|
||||
this.autoCreate = autoCreate;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(this.beanFactory, "'beanFactory' must not be null");
|
||||
if (!autoCreate){
|
||||
return;
|
||||
}
|
||||
else {
|
||||
AutoCreateCandidatesCollector channelCandidatesCollector =
|
||||
(AutoCreateCandidatesCollector) beanFactory.getBean(AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME, AutoCreateCandidatesCollector.class);
|
||||
Assert.notNull(channelCandidatesCollector, "Failed to locate '" +
|
||||
ChannelInitializer.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
|
||||
// at this point channelNames are all resolved with placeholders and SpEL
|
||||
Collection<String> channelNames = channelCandidatesCollector.getChannelNames();
|
||||
if (channelNames != null){
|
||||
for (String channelName : channelNames) {
|
||||
if (!beanFactory.containsBean(channelName)){
|
||||
if (this.logger.isDebugEnabled()){
|
||||
this.logger.debug("Auto-creating channel '" + channelName + "' as DirectChannel");
|
||||
}
|
||||
RootBeanDefinition messageChannel = new RootBeanDefinition();
|
||||
messageChannel.setBeanClass(DirectChannel.class);
|
||||
BeanDefinitionHolder messageChannelHolder = new BeanDefinitionHolder(messageChannel, channelName);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(messageChannelHolder, (BeanDefinitionRegistry) this.beanFactory);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Collects candidate channel names to be auto-created by ChannelInitializer
|
||||
*/
|
||||
static class AutoCreateCandidatesCollector {
|
||||
|
||||
private final Collection<String> channelNames;
|
||||
|
||||
public AutoCreateCandidatesCollector(Collection<String> channelNames){
|
||||
this.channelNames = channelNames;
|
||||
}
|
||||
|
||||
public Collection<String> getChannelNames() {
|
||||
return channelNames;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -16,20 +16,27 @@
|
||||
|
||||
package org.springframework.integration.channel;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageChannel;
|
||||
import org.springframework.integration.core.MessageHandler;
|
||||
import org.springframework.integration.dispatcher.RoundRobinLoadBalancingStrategy;
|
||||
import org.springframework.integration.dispatcher.UnicastingDispatcher;
|
||||
import org.springframework.integration.endpoint.EventDrivenConsumer;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
@@ -68,6 +75,55 @@ public class DirectChannelTests {
|
||||
assertEquals("test-thread", target.threadName);
|
||||
}
|
||||
|
||||
@Test // See INT-2434
|
||||
public void testChannelCreationWithBeanDefinitionOverrideTrue() throws Exception {
|
||||
ClassPathXmlApplicationContext parentContext = new ClassPathXmlApplicationContext("parent-config.xml", this.getClass());
|
||||
MessageChannel parentChannelA = parentContext.getBean("parentChannelA", MessageChannel.class);
|
||||
MessageChannel parentChannelB = parentContext.getBean("parentChannelB", MessageChannel.class);
|
||||
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
|
||||
context.setAllowBeanDefinitionOverriding(false);
|
||||
context.setConfigLocations(new String[]{"classpath:org/springframework/integration/channel/channel-override-config.xml"});
|
||||
context.setParent(parentContext);
|
||||
Method method = ReflectionUtils.findMethod(ClassPathXmlApplicationContext.class, "obtainFreshBeanFactory");
|
||||
method.setAccessible(true);
|
||||
method.invoke(context);
|
||||
assertFalse(context.containsBean("channelA"));
|
||||
assertFalse(context.containsBean("channelB"));
|
||||
assertTrue(context.containsBean("channelC"));
|
||||
assertTrue(context.containsBean("channelD"));
|
||||
|
||||
context.refresh();
|
||||
|
||||
PublishSubscribeChannel channelEarly = context.getBean("channelEarly", PublishSubscribeChannel.class);
|
||||
|
||||
assertTrue(context.containsBean("channelA"));
|
||||
assertTrue(context.containsBean("channelB"));
|
||||
assertTrue(context.containsBean("channelC"));
|
||||
assertTrue(context.containsBean("channelD"));
|
||||
EventDrivenConsumer consumerA = context.getBean("serviceA", EventDrivenConsumer.class);
|
||||
assertEquals(context.getBean("channelA"), TestUtils.getPropertyValue(consumerA, "inputChannel"));
|
||||
assertEquals(context.getBean("channelB"), TestUtils.getPropertyValue(consumerA, "handler.outputChannel"));
|
||||
|
||||
EventDrivenConsumer consumerB = context.getBean("serviceB", EventDrivenConsumer.class);
|
||||
assertEquals(context.getBean("channelB"), TestUtils.getPropertyValue(consumerB, "inputChannel"));
|
||||
assertEquals(context.getBean("channelC"), TestUtils.getPropertyValue(consumerB, "handler.outputChannel"));
|
||||
|
||||
EventDrivenConsumer consumerC = context.getBean("serviceC", EventDrivenConsumer.class);
|
||||
assertEquals(context.getBean("channelC"), TestUtils.getPropertyValue(consumerC, "inputChannel"));
|
||||
assertEquals(context.getBean("channelD"), TestUtils.getPropertyValue(consumerC, "handler.outputChannel"));
|
||||
|
||||
EventDrivenConsumer consumerD = context.getBean("serviceD", EventDrivenConsumer.class);
|
||||
assertEquals(parentChannelA, TestUtils.getPropertyValue(consumerD, "inputChannel"));
|
||||
assertEquals(parentChannelB, TestUtils.getPropertyValue(consumerD, "handler.outputChannel"));
|
||||
|
||||
EventDrivenConsumer consumerE = context.getBean("serviceE", EventDrivenConsumer.class);
|
||||
assertEquals(parentChannelB, TestUtils.getPropertyValue(consumerE, "inputChannel"));
|
||||
|
||||
EventDrivenConsumer consumerF = context.getBean("serviceF", EventDrivenConsumer.class);
|
||||
assertEquals(channelEarly, TestUtils.getPropertyValue(consumerF, "inputChannel"));
|
||||
}
|
||||
|
||||
|
||||
private static class ThreadNameExtractingTestTarget implements MessageHandler {
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
|
||||
|
||||
<context:property-placeholder properties-ref="props"/>
|
||||
|
||||
<util:properties id="props">
|
||||
<prop key="channelC" >channelC</prop>
|
||||
<prop key="channelB" >channelB</prop>
|
||||
</util:properties>
|
||||
|
||||
<int:service-activator id="serviceA" input-channel="channelA" output-channel="#{'channelB'}" expression="''"/>
|
||||
|
||||
<int:service-activator id="serviceB" input-channel="#{'channelB'}" output-channel="${channelC}" expression="''"/>
|
||||
|
||||
<int:service-activator id="serviceC" input-channel="${channelC}" output-channel="#{@channelD.getComponentName()}" expression="''"/>
|
||||
|
||||
<int:service-activator id="serviceD" input-channel="parentChannelA" output-channel="#{@parentChannelB.getComponentName()}" expression="''"/>
|
||||
|
||||
<int:service-activator id="serviceE" input-channel="#{'parentChannelB'}" expression="''"/>
|
||||
|
||||
<int:publish-subscribe-channel id="channelEarly"/>
|
||||
|
||||
<int:service-activator id="serviceF" input-channel="channelEarly" expression="''"/>
|
||||
|
||||
<int:channel id="channelC"/>
|
||||
|
||||
<int:channel id="channelD"/>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
|
||||
|
||||
<int:channel id="parentChannelA"/>
|
||||
|
||||
<int:channel id="parentChannelB"/>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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 org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
/**
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
*
|
||||
*/
|
||||
public class ChannelAutoCreationTests {
|
||||
|
||||
@Test // no assertions since it validates that no exception is thrown
|
||||
public void testEnablingAutoChannelCreationBeforeWithCustom(){
|
||||
new ClassPathXmlApplicationContext("TestEnableChannelAutoCreation-before-context.xml", this.getClass());
|
||||
}
|
||||
|
||||
@Test // no assertions since it validates that no exception is thrown
|
||||
public void testEnablingAutoChannelCreationAfterWithCustom(){
|
||||
new ClassPathXmlApplicationContext("TestEnableChannelAutoCreation-after-context.xml", this.getClass());
|
||||
}
|
||||
|
||||
@Test(expected=BeanCreationException.class)
|
||||
public void testDisablingAutoChannelCreationAfter(){
|
||||
new ClassPathXmlApplicationContext("TestDisableChannelAutoCreation-after-context.xml", this.getClass());
|
||||
}
|
||||
|
||||
@Test(expected=BeanCreationException.class)
|
||||
public void testDisablingAutoChannelCreationBefore(){
|
||||
new ClassPathXmlApplicationContext("TestDisableChannelAutoCreation-before-context.xml", this.getClass());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.1.xsd">
|
||||
|
||||
<int:service-activator input-channel="inputChannel" expression="'hello'"/>
|
||||
|
||||
<bean id="ChannelInitializer" class="org.springframework.integration.config.xml.ChannelInitializer">
|
||||
<property name="autoCreate" value="false"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.1.xsd">
|
||||
|
||||
<bean id="ChannelInitializer" class="org.springframework.integration.config.xml.ChannelInitializer">
|
||||
<property name="autoCreate" value="false"/>
|
||||
</bean>
|
||||
|
||||
<int:service-activator input-channel="inputChannel" expression="'hello'"/>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.1.xsd">
|
||||
|
||||
<int:service-activator input-channel="inputChannel" expression="'hello'"/>
|
||||
|
||||
<bean id="ChannelInitializer" class="org.springframework.integration.config.xml.ChannelInitializer">
|
||||
<property name="autoCreate" value="true"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.1.xsd">
|
||||
|
||||
<bean id="ChannelInitializer" class="org.springframework.integration.config.xml.ChannelInitializer">
|
||||
<property name="autoCreate" value="true"/>
|
||||
</bean>
|
||||
|
||||
<int:service-activator input-channel="inputChannel" expression="'hello'"/>
|
||||
|
||||
</beans>
|
||||
@@ -12,16 +12,19 @@
|
||||
*/
|
||||
package org.springframework.integration.jmx.config;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.integration.monitor.IntegrationMBeanExporter;
|
||||
import org.springframework.jmx.export.MBeanExporter;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -31,24 +34,43 @@ import org.springframework.util.StringUtils;
|
||||
* It helps in eliminating conflicts when more than one MBeanExporter is present. It creates a list
|
||||
* of bean names that will be exported by the IntegrationMBeanExporter and merges it with the list
|
||||
* of 'excludedBeans' of MBeanExporter so it will not attempt to export them again.
|
||||
*
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
* @since 2.1
|
||||
*
|
||||
*/
|
||||
class MBeanExporterHelper implements BeanFactoryPostProcessor, BeanPostProcessor, PriorityOrdered {
|
||||
class MBeanExporterHelper implements BeanFactoryPostProcessor,
|
||||
BeanPostProcessor, Ordered, BeanFactoryAware {
|
||||
|
||||
private final static String EXCLUDED_BEANS_PROPERTY_NAME = "excludedBeans";
|
||||
|
||||
private final static String SI_ROOT_PACKAGE = "org.springframework.integration.";
|
||||
|
||||
private final Set<String> siBeanNames = new HashSet<String>();
|
||||
|
||||
private volatile BeanFactory beanFactory;
|
||||
|
||||
private volatile boolean capturedAutoChannelCandidates;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof MBeanExporter && !(bean instanceof IntegrationMBeanExporter)){
|
||||
if (!this.capturedAutoChannelCandidates && this.beanFactory != null) {
|
||||
Object autoCreateChannelCandidates = beanFactory.getBean("$autoCreateChannelCandidates");
|
||||
if (autoCreateChannelCandidates != null){
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<String> autoCreateChannelCandidatesNames =
|
||||
(Collection<String>) new DirectFieldAccessor(autoCreateChannelCandidates).getPropertyValue("channelNames");
|
||||
this.siBeanNames.addAll(autoCreateChannelCandidatesNames);
|
||||
}
|
||||
this.capturedAutoChannelCandidates = true;
|
||||
}
|
||||
if (bean instanceof MBeanExporter && !(bean instanceof IntegrationMBeanExporter)) {
|
||||
MBeanExporter mbeanExporter = (MBeanExporter) bean;
|
||||
DirectFieldAccessor mbeDfa = new DirectFieldAccessor(mbeanExporter);
|
||||
@SuppressWarnings("unchecked")
|
||||
Set<String> excludedNames = (Set<String>) mbeDfa.getPropertyValue(EXCLUDED_BEANS_PROPERTY_NAME);
|
||||
if (excludedNames != null) {
|
||||
siBeanNames.addAll(excludedNames);
|
||||
@@ -79,6 +101,6 @@ class MBeanExporterHelper implements BeanFactoryPostProcessor, BeanPostProcessor
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return Integer.MIN_VALUE;
|
||||
return Ordered.HIGHEST_PRECEDENCE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,9 +34,10 @@ import org.springframework.jmx.export.MBeanExporter;
|
||||
*/
|
||||
public class Int2307Tests {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testInt2307_DefaultMBeanExporter() throws Exception{
|
||||
new ClassPathXmlApplicationContext("single-config.xml", this.getClass());
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("single-config.xml", this.getClass());
|
||||
List<MBeanServer> servers = MBeanServerFactory.findMBeanServer(null);
|
||||
assertEquals(1, servers.size());
|
||||
MBeanServer server = servers.get(0);
|
||||
@@ -61,6 +62,11 @@ public class Int2307Tests {
|
||||
assertEquals(0xf, bits);
|
||||
assertEquals(4, count);
|
||||
|
||||
Class<?> clazz = Class.forName("org.springframework.integration.jmx.config.MBeanExporterHelper");
|
||||
Object mBeanExporterHelper = context.getBean(clazz);
|
||||
assertTrue(((Set<String>)TestUtils.getPropertyValue(mBeanExporterHelper, "siBeanNames")).contains("z"));
|
||||
assertTrue(((Set<String>)TestUtils.getPropertyValue(mBeanExporterHelper, "siBeanNames")).contains("zz"));
|
||||
|
||||
// make sure there are no duplicate MBean ObjectNames if 2 contexts loaded from same config
|
||||
new ClassPathXmlApplicationContext("single-config.xml", this.getClass());
|
||||
}
|
||||
@@ -76,7 +82,10 @@ public class Int2307Tests {
|
||||
assertTrue(excludedBeanNames.contains("x"));
|
||||
assertTrue(excludedBeanNames.contains("y"));
|
||||
assertTrue(excludedBeanNames.contains("foo")); // non SI bean
|
||||
Class<?> clazz = Class.forName("org.springframework.integration.jmx.config.MBeanExporterHelper");
|
||||
Object mBeanExporterHelper = context.getBean(clazz);
|
||||
assertTrue(((Set<String>)TestUtils.getPropertyValue(mBeanExporterHelper, "siBeanNames")).contains("z"));
|
||||
}
|
||||
|
||||
|
||||
public static class Foo{}
|
||||
}
|
||||
|
||||
@@ -24,18 +24,20 @@
|
||||
<bean id="myExporter" class="org.springframework.jmx.export.MBeanExporter">
|
||||
<property name="excludedBeans" value="foo"/>
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="foo" class="org.springframework.integration_.mbeanexporterhelper.Int2307Tests.Foo"/>
|
||||
|
||||
|
||||
<int:recipient-list-router id="rlr" input-channel="x">
|
||||
<int:recipient channel="y"/>
|
||||
</int:recipient-list-router>
|
||||
|
||||
|
||||
<int:header-value-router id="hvr" input-channel="x" header-name="ghgf">
|
||||
<int:mapping value="foo" channel="y"/>
|
||||
</int:header-value-router>
|
||||
|
||||
<int:channel id="x" />
|
||||
<int:channel id="y" />
|
||||
|
||||
|
||||
<int:service-activator input-channel="z" expression="''"/>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -22,16 +22,26 @@
|
||||
</util:properties>
|
||||
|
||||
<context:mbean-export/>
|
||||
|
||||
|
||||
<int:recipient-list-router id="rlr" input-channel="x">
|
||||
<int:recipient channel="y"/>
|
||||
</int:recipient-list-router>
|
||||
|
||||
|
||||
<int:header-value-router id="hvr" input-channel="x" header-name="ghgf">
|
||||
<int:mapping value="foo" channel="y"/>
|
||||
</int:header-value-router>
|
||||
|
||||
<int:channel id="x" />
|
||||
<int:channel id="y" />
|
||||
|
||||
|
||||
<int:service-activator input-channel="z" expression="''"/>
|
||||
|
||||
<int:service-activator input-channel="${zz}" expression="''"/>
|
||||
|
||||
<util:properties id="placeholders">
|
||||
<prop key="zz">zz</prop>
|
||||
</util:properties>
|
||||
|
||||
<context:property-placeholder properties-ref="placeholders"/>
|
||||
|
||||
</beans>
|
||||
|
||||
Reference in New Issue
Block a user