From d67a59e3db70c0e7eba6ef0d44480fc73a85a7df Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Tue, 16 Dec 2008 19:50:07 +0000 Subject: [PATCH] Added namespace support for 'logging-channel-adapter' (INT-524). Moved default bean configuration into a BeanFactoryPostProcessor (INT-525). This also enables resolution of issue INT-520. --- ...dChannelAdapterWithPatternParserTests.java | 2 + .../MessagePublishingErrorHandler.java | 4 +- ...ltConfiguringBeanFactoryPostProcessor.java | 114 ++++++++++++++++++ .../xml/IntegrationNamespaceHandler.java | 57 +++------ .../config/xml/spring-integration-1.0.xsd | 36 +++++- 5 files changed, 170 insertions(+), 43 deletions(-) create mode 100644 org.springframework.integration/src/main/java/org/springframework/integration/config/xml/DefaultConfiguringBeanFactoryPostProcessor.java diff --git a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/FileInboundChannelAdapterWithPatternParserTests.java b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/FileInboundChannelAdapterWithPatternParserTests.java index f5a4414285..60ccf3832a 100644 --- a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/FileInboundChannelAdapterWithPatternParserTests.java +++ b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/FileInboundChannelAdapterWithPatternParserTests.java @@ -30,6 +30,7 @@ import org.junit.runner.RunWith; import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationContext; import org.springframework.integration.core.MessageChannel; import org.springframework.integration.endpoint.AbstractEndpoint; @@ -52,6 +53,7 @@ public class FileInboundChannelAdapterWithPatternParserTests { private ApplicationContext context; @Autowired(required=true) + @Qualifier("adapterWithPattern.adapter") private AbstractEndpoint endpoint; private DirectFieldAccessor accessor; diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/channel/MessagePublishingErrorHandler.java b/org.springframework.integration/src/main/java/org/springframework/integration/channel/MessagePublishingErrorHandler.java index 4b580cbe09..786164fa15 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/channel/MessagePublishingErrorHandler.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/channel/MessagePublishingErrorHandler.java @@ -86,7 +86,9 @@ public class MessagePublishingErrorHandler implements ErrorHandler, BeanFactoryA } } catch (Throwable errorDeliveryError) { // message will be logged only - logger.error("Error message was not delivered, it will be dumped in the error log", errorDeliveryError); + if (logger.isWarnEnabled()) { + logger.warn("Error message was not delivered.", errorDeliveryError); + } } } if (!sent && logger.isErrorEnabled()) { diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/DefaultConfiguringBeanFactoryPostProcessor.java b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/DefaultConfiguringBeanFactoryPostProcessor.java new file mode 100644 index 0000000000..2adf51f3af --- /dev/null +++ b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/DefaultConfiguringBeanFactoryPostProcessor.java @@ -0,0 +1,114 @@ +/* + * 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.xml; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.BeansException; +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.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.core.task.TaskExecutor; +import org.springframework.integration.context.IntegrationContextUtils; + +/** + * A {@link BeanFactoryPostProcessor} implementation that provides default + * beans for the error handling and task scheduling if those beans have not + * already been explicitly defined within the registry. + * + * @author Mark Fisher + */ +class DefaultConfiguringBeanFactoryPostProcessor implements BeanFactoryPostProcessor { + + private Log logger = LogFactory.getLog(this.getClass()); + + + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + if (beanFactory instanceof BeanDefinitionRegistry) { + BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; + this.registerErrorChannelIfNecessary(registry); + this.registerTaskSchedulerIfNecessary(registry); + } + else if (logger.isWarnEnabled()) { + logger.warn("BeanFactory is not a BeanDefinitionRegistry. The default '" + + IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME + "' and '" + + IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME + "' cannot be configured."); + } + } + + /** + * Register an error channel in the given BeanDefinitionRegistry if not yet present. + * The bean name for which this is checking is defined by the constant + * {@link IntegrationContextUtils#ERROR_CHANNEL_BEAN_NAME}. + */ + private void registerErrorChannelIfNecessary(BeanDefinitionRegistry registry) { + if (!registry.isBeanNameInUse(IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME)) { + if (logger.isInfoEnabled()) { + logger.info("No bean named '" + IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME + + "' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created."); + } + RootBeanDefinition errorChannelDef = new RootBeanDefinition(); + errorChannelDef.setBeanClassName(IntegrationNamespaceUtils.BASE_PACKAGE + ".channel.PublishSubscribeChannel"); + BeanDefinitionHolder errorChannelHolder = new BeanDefinitionHolder( + errorChannelDef, IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME); + BeanDefinitionReaderUtils.registerBeanDefinition(errorChannelHolder, registry); + BeanDefinitionBuilder loggingHandlerBuilder = BeanDefinitionBuilder.genericBeanDefinition( + IntegrationNamespaceUtils.BASE_PACKAGE + ".handler.LoggingHandler"); + loggingHandlerBuilder.addConstructorArgValue("ERROR"); + String loggingHandlerBeanName = BeanDefinitionReaderUtils.registerWithGeneratedName( + loggingHandlerBuilder.getBeanDefinition(), registry); + BeanDefinitionBuilder loggingEndpointBuilder = BeanDefinitionBuilder.genericBeanDefinition( + IntegrationNamespaceUtils.BASE_PACKAGE + ".endpoint.EventDrivenConsumer"); + loggingEndpointBuilder.addConstructorArgReference(IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME); + loggingEndpointBuilder.addConstructorArgReference(loggingHandlerBeanName); + BeanDefinitionReaderUtils.registerWithGeneratedName(loggingEndpointBuilder.getBeanDefinition(), registry); + } + } + + /** + * Register a TaskScheduler in the given BeanDefinitionRegistry if not yet present. + * The bean name for which this is checking is defined by the constant + * {@link IntegrationContextUtils#TASK_SCHEDULER_BEAN_NAME}. + */ + private void registerTaskSchedulerIfNecessary(BeanDefinitionRegistry registry) { + if (!registry.isBeanNameInUse(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME)) { + if (logger.isInfoEnabled()) { + logger.info("No bean named '" + IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME + + "' has been explicitly defined. Therefore, a default SimpleTaskScheduler will be created."); + } + TaskExecutor taskExecutor = IntegrationContextUtils.createThreadPoolTaskExecutor(2, 100, 0, "task-scheduler-"); + BeanDefinitionBuilder schedulerBuilder = BeanDefinitionBuilder.genericBeanDefinition( + IntegrationNamespaceUtils.BASE_PACKAGE + ".scheduling.SimpleTaskScheduler"); + schedulerBuilder.addConstructorArgValue(taskExecutor); + BeanDefinitionBuilder errorHandlerBuilder = BeanDefinitionBuilder.genericBeanDefinition( + IntegrationNamespaceUtils.BASE_PACKAGE + ".channel.MessagePublishingErrorHandler"); + errorHandlerBuilder.addPropertyReference("defaultErrorChannel", IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME); + String errorHandlerBeanName = BeanDefinitionReaderUtils.registerWithGeneratedName( + errorHandlerBuilder.getBeanDefinition(), registry); + schedulerBuilder.addPropertyReference("errorHandler", errorHandlerBeanName); + BeanDefinitionHolder schedulerHolder = new BeanDefinitionHolder( + schedulerBuilder.getBeanDefinition(), IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME); + BeanDefinitionReaderUtils.registerBeanDefinition(schedulerHolder, registry); + } + } + +} diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceHandler.java b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceHandler.java index 28b8881de8..03c97c7ba9 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceHandler.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceHandler.java @@ -23,16 +23,9 @@ 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.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.NamespaceHandler; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.core.task.TaskExecutor; -import org.springframework.integration.channel.MessagePublishingErrorHandler; -import org.springframework.integration.channel.PublishSubscribeChannel; -import org.springframework.integration.context.IntegrationContextUtils; -import org.springframework.integration.scheduling.SimpleTaskScheduler; /** * Namespace handler for the integration namespace. @@ -42,52 +35,39 @@ import org.springframework.integration.scheduling.SimpleTaskScheduler; */ public class IntegrationNamespaceHandler implements NamespaceHandler { - private volatile boolean initializedContext; - private final NamespaceHandlerSupport delegate = new NamespaceHandlerDelegate(); + private volatile boolean initialized; + + private final Object initializationMonitor = new Object(); + public void init() { this.delegate.init(); } public BeanDefinition parse(Element element, ParserContext parserContext) { - if (!this.initializedContext) { - registerTaskSchedulerIfNecessary(parserContext.getRegistry()); - this.initializedContext = true; + if (!this.initialized) { + this.registerDefaultConfiguringBeanFactoryPostProcessor(parserContext); } return this.delegate.parse(element, parserContext); - } + } public BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder definition, ParserContext parserContext) { return this.delegate.decorate(source, definition, parserContext); } - /** - * Register a TaskScheduler in the given BeanDefinitionRegistry if not yet present. - * The bean name for which this is checking is defined by the constant - * {@link IntegrationContextUtils#TASK_SCHEDULER_BEAN_NAME}. - */ - private static void registerTaskSchedulerIfNecessary(BeanDefinitionRegistry registry) { - if (!registry.containsBeanDefinition(IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME)) { - RootBeanDefinition errorChannelDef = new RootBeanDefinition(PublishSubscribeChannel.class); - BeanDefinitionHolder errorChannelHolder = new BeanDefinitionHolder( - errorChannelDef, IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME); - BeanDefinitionReaderUtils.registerBeanDefinition(errorChannelHolder, registry); - } - TaskExecutor taskExecutor = null; - if (!registry.containsBeanDefinition(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME)) { - taskExecutor = IntegrationContextUtils.createThreadPoolTaskExecutor(2, 100, 0, "task-scheduler-"); - BeanDefinitionBuilder schedulerBuilder = BeanDefinitionBuilder.genericBeanDefinition(SimpleTaskScheduler.class); - schedulerBuilder.addConstructorArgValue(taskExecutor); - BeanDefinitionBuilder errorHandlerBuilder = BeanDefinitionBuilder.genericBeanDefinition(MessagePublishingErrorHandler.class); - errorHandlerBuilder.addPropertyReference("defaultErrorChannel", IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME); - String errorHandlerBeanName = BeanDefinitionReaderUtils.registerWithGeneratedName( - errorHandlerBuilder.getBeanDefinition(), registry); - schedulerBuilder.addPropertyReference("errorHandler", errorHandlerBeanName); - BeanDefinitionHolder schedulerHolder = new BeanDefinitionHolder( - schedulerBuilder.getBeanDefinition(), IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME); - BeanDefinitionReaderUtils.registerBeanDefinition(schedulerHolder, registry); + private void registerDefaultConfiguringBeanFactoryPostProcessor(ParserContext parserContext) { + synchronized (this.initializationMonitor) { + if (!this.initialized) { + String postProcessorSimpleClassName = "DefaultConfiguringBeanFactoryPostProcessor"; + BeanDefinitionBuilder postProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition( + IntegrationNamespaceUtils.BASE_PACKAGE + ".config.xml." + postProcessorSimpleClassName); + BeanDefinitionHolder postProcessorHolder = new BeanDefinitionHolder(postProcessorBuilder.getBeanDefinition(), + IntegrationNamespaceUtils.BASE_PACKAGE + ".internal" + postProcessorSimpleClassName); + BeanDefinitionReaderUtils.registerBeanDefinition(postProcessorHolder, parserContext.getRegistry()); + this.initialized = true; + } } } @@ -111,6 +91,7 @@ public class IntegrationNamespaceHandler implements NamespaceHandler { registerBeanDefinitionParser("payload-deserializing-transformer", new PayloadDeserializingTransformerParser()); registerBeanDefinitionParser("inbound-channel-adapter", new MethodInvokingInboundChannelAdapterParser()); registerBeanDefinitionParser("outbound-channel-adapter", new MethodInvokingOutboundChannelAdapterParser()); + registerBeanDefinitionParser("logging-channel-adapter", new LoggingChannelAdapterParser()); registerBeanDefinitionParser("gateway", new GatewayParser()); registerBeanDefinitionParser("bridge", new BridgeParser()); registerBeanDefinitionParser("chain", new ChainParser()); diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/spring-integration-1.0.xsd b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/spring-integration-1.0.xsd index d3dee164f0..d906d7bd00 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/spring-integration-1.0.xsd +++ b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/spring-integration-1.0.xsd @@ -182,7 +182,7 @@ - + Defines a Channel Adapter that receives from a MessageSource and sends to a MessageChannel. @@ -190,7 +190,7 @@ - + Defines a Channel Adapter that receives from a MessageChannel and sends to a MessageConsumer. @@ -198,6 +198,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -212,8 +242,6 @@ - -