INT-2500: Add Support for Global Properties

`META-INF/spring.integration.properties`

JIRA: https://jira.springsource.org/browse/INT-2500
This commit is contained in:
Artem Bilan
2013-11-15 18:30:13 +02:00
committed by Gary Russell
parent 9c42a65e3c
commit afb369c0eb
8 changed files with 179 additions and 0 deletions

View File

@@ -16,6 +16,11 @@
package org.springframework.integration.config.xml;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Element;
@@ -24,8 +29,10 @@ import org.w3c.dom.Node;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
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.ManagedSet;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
@@ -33,6 +40,9 @@ 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.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.integration.channel.registry.DefaultHeaderChannelRegistry;
import org.springframework.integration.config.IntegrationEvaluationContextFactoryBean;
import org.springframework.integration.config.xml.ChannelInitializer.AutoCreateCandidatesCollector;
@@ -72,12 +82,47 @@ public abstract class AbstractIntegrationNamespaceHandler implements NamespaceHa
this.verifySchemaVersion(element, parserContext);
this.registerImplicitChannelCreator(parserContext);
this.registerIntegrationEvaluationContext(parserContext);
this.registerIntegrationProperties(parserContext);
this.registerHeaderChannelRegistry(parserContext);
this.registerBuiltInBeans(parserContext);
this.registerDefaultConfiguringBeanFactoryPostProcessorIfNecessary(parserContext);
return this.delegate.parse(element, parserContext);
}
private void registerIntegrationProperties(ParserContext parserContext) {
boolean alreadyRegistered = false;
BeanDefinitionRegistry registry = parserContext.getRegistry();
if (registry instanceof ListableBeanFactory) {
alreadyRegistered = ((ListableBeanFactory) registry)
.containsBean(IntegrationContextUtils.INTEGRATION_PROPERTIES_BEAN_NAME);
}
else {
alreadyRegistered = registry.isBeanNameInUse(IntegrationContextUtils.INTEGRATION_PROPERTIES_BEAN_NAME);
}
if (!alreadyRegistered) {
ResourcePatternResolver resourceResolver =
new PathMatchingResourcePatternResolver(parserContext.getReaderContext().getBeanClassLoader());
try {
Resource[] defaultResources = resourceResolver.getResources("classpath*:META-INF/spring.integration.default.properties");
Resource[] userResources = resourceResolver.getResources("classpath*:META-INF/spring.integration.properties");
List<Resource> resources = new LinkedList<Resource>(Arrays.asList(defaultResources));
resources.addAll(Arrays.asList(userResources));
BeanDefinitionBuilder integrationPropertiesBuilder = BeanDefinitionBuilder
.genericBeanDefinition(PropertiesFactoryBean.class)
.addPropertyValue("locations", resources);
registry.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_PROPERTIES_BEAN_NAME,
integrationPropertiesBuilder.getBeanDefinition());
}
catch (IOException e) {
parserContext.getReaderContext().warning("Cannot load 'spring.integration.properties' Resources.", null, e);
}
}
}
@Override
public final BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder definition, ParserContext parserContext) {
return this.delegate.decorate(source, definition, parserContext);

View File

@@ -16,6 +16,8 @@
package org.springframework.integration.context;
import java.util.Properties;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.expression.spel.support.StandardEvaluationContext;
@@ -47,6 +49,9 @@ public abstract class IntegrationContextUtils {
public static final String INTEGRATION_HEADER_CHANNEL_REGISTRY_BEAN_NAME = "integrationHeaderChannelRegistry";
public static final String INTEGRATION_PROPERTIES_BEAN_NAME = "integrationProperties";
private static final Properties EMPTY_PROPERTIES = new Properties();
/**
* Return the {@link MetadataStore} bean whose name is "metadataStore".
@@ -107,4 +112,24 @@ public abstract class IntegrationContextUtils {
return beanFactory.getBean(beanName, type);
}
/**
* @return the global {@link IntegrationContextUtils#INTEGRATION_PROPERTIES_BEAN_NAME}
* bean from provided {@code #beanFactory}, which represents the merged
* properties values from all 'META-INF/spring.integration.default.properties'
* and 'META-INF/spring.integration.properties'.
* May return {@link IntegrationContextUtils#EMPTY_PROPERTIES} if there is no
* {@link IntegrationContextUtils#INTEGRATION_PROPERTIES_BEAN_NAME} bean within
* provided {@code #beanFactory} or provided {@code #beanFactory} is null.
*/
public static Properties getIntegrationProperties(BeanFactory beanFactory) {
Properties properties = null;
if (beanFactory != null) {
properties = getBeanOfType(beanFactory, INTEGRATION_PROPERTIES_BEAN_NAME, Properties.class);
}
if (properties == null) {
properties = EMPTY_PROPERTIES;
}
return properties;
}
}

View File

@@ -16,6 +16,8 @@
package org.springframework.integration.context;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -47,6 +49,7 @@ import org.springframework.util.StringUtils;
* @author Josh Long
* @author Stefan Ferstl
* @author Gary Russell
* @author Artem Bilan
*/
public abstract class IntegrationObjectSupport implements BeanNameAware, NamedComponent,
ApplicationContextAware, BeanFactoryAware, InitializingBean {
@@ -169,6 +172,13 @@ public abstract class IntegrationObjectSupport implements BeanNameAware, NamedCo
return this.applicationContext == null ? null : this.applicationContext.getId();
}
/**
* @see IntegrationContextUtils#getIntegrationProperties
*/
protected Properties getIntegrationProperties() {
return IntegrationContextUtils.getIntegrationProperties(this.beanFactory);
}
@Override
public String toString() {
return (this.beanName != null) ? this.beanName : super.toString();

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2013 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.context;
/**
* Convention Enumeration to represent keys from 'META-INF/spring.integration.properties'.
*
* @author Artem Bilan
* @since 3.0
*/
public interface IntegrationProperties {
String LATE_REPLY_LOGGING_LEVEL = "messagingTemplate.lateReply.logging.level";
}

View File

@@ -0,0 +1 @@
messagingTemplate.lateReply.logging.level=warn

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
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">
<channel id="foo"/>
<service-activator id="fooService" input-channel="foo" output-channel="nullChannel" expression="'foo'"/>
</beans:beans>

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2013 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.context;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import java.util.Properties;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Artem Bilan
* @since 3.0
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class IntegrationContextTests {
@Autowired
@Qualifier(IntegrationContextUtils.INTEGRATION_PROPERTIES_BEAN_NAME)
private Properties integrationProperties;
@Autowired
@Qualifier("fooService")
private IntegrationObjectSupport serviceActivator;
@Test
public void testIntegrationContextComponents() {
assertEquals("error", this.integrationProperties.get(IntegrationProperties.LATE_REPLY_LOGGING_LEVEL));
assertSame(this.integrationProperties, this.serviceActivator.getIntegrationProperties());
}
}

View File

@@ -0,0 +1 @@
messagingTemplate.lateReply.logging.level=error