Add Spring PropertySource integration + tests to prove it works

This commit is contained in:
Tim Donohue
2018-10-18 15:36:19 -05:00
parent 673d4b9d36
commit 79d027776e
5 changed files with 120 additions and 21 deletions

View File

@@ -0,0 +1,36 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.servicemanager.config;
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.configuration2.spring.ConfigurationPropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.MutablePropertySources;
/**
* Extends Spring PropertySourcesPlaceholderConfigurer to allow our Configuration to be included as a Spring
* PropertySource. This allows ${...} placeholders within bean definition property values and @Value annotations
* to be resolved using DSpaceConfigurationService
* <P>
* See: https://stackoverflow.com/a/36718301/3750035
* <P>
* NOTE: This is initialized in spring-dspace-core-services.xml
*
* @see PropertySourcesPlaceholderConfigurer
* @see DSpaceConfigurationService
*/
public class DSpaceConfigurationPlaceholderConfigurer extends PropertySourcesPlaceholderConfigurer {
public DSpaceConfigurationPlaceholderConfigurer(Configuration configuration) {
ConfigurationPropertySource apacheCommonsConfigPropertySource =
new ConfigurationPropertySource(configuration.getClass().getName(), configuration);
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addLast(apacheCommonsConfigPropertySource);
setPropertySources(propertySources);
}
}

View File

@@ -16,22 +16,8 @@
<!-- Place all DSpace core service bean definitions below here -->
<!-- PROPERTY PLACEHOLDER SETUP -->
<!-- The following two beans are a cool trick. They let us use dynamic properties
like ${dspace.dir} within our Spring bean XML configuration files. These
property values are then dynamically loaded via our DSpaceConfigurationService. -->
<!-- First, configure a property placeholder. This lets us use properties like ${..} within Spring bean configs -->
<!--<bean id="propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" ref="dspaceConfigurationFactoryBean"/>
</bean>-->
<!-- Next, wire it up to use our DSpaceConfigurationFactoryBean. This bean will use our configured
DSpace ConfigurationService for all property substitution in Spring XML files -->
<!--<bean id="dspaceConfigurationFactoryBean" class="org.dspace.servicemanager.config.DSpaceConfigurationFactoryBean">
<constructor-arg ref="org.dspace.services.ConfigurationService"/>
</bean>-->
<!-- Configure the Commmons Configuration "ConfigurationPropertiesFactoryBean" to use our DSpace Configuration
service to perform Property Placeholder substitution in Spring configuration. For example, this lets us
service to perform Property Placeholder substitution in Spring configuration. For example, this lets us
use dynamic properties like ${dspace.dir} within our Spring bean XML configuration files. These property
values are then dynamically loaded via our DSpaceConfigurationService at runtime. -->
<!-- See: https://commons.apache.org/proper/commons-configuration/userguide/howto_utilities.html#Use_Configuration_in_Spring -->
@@ -44,8 +30,16 @@
</bean>
</property>
</bean>
<!-- Configure a custom PropertySourcesPlaceholderConfigurer to also use our DSpaceConfigurationService. This
allows us to also resolve ${...} placeholders in both Bean definitions property values and @Value annotations
using our DSpaceConfigurationService. Again, these are resolved at runtime. -->
<bean id="dspaceConfigurationFactoryBean" class="org.dspace.servicemanager.config.DSpaceConfigurationPlaceholderConfigurer">
<constructor-arg>
<ref bean="dspaceConfiguration" />
</constructor-arg>
</bean>
<!-- This wires up our ConfigurationService.getConfiguration() method to be called to provide its properties
to the above PropertyPlaceholderConfigurer -->
to the above PropertyPlaceholderConfigurer and PropertySourcesPlaceholderConfigurer beans. -->
<bean id="dspaceConfiguration" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="org.dspace.services.ConfigurationService" />
<property name="targetMethod" value="getConfiguration" />

View File

@@ -42,7 +42,7 @@ public class DSpaceConfigurationBeanTest
/**
* Test that property substitution is working properly in Spring XML configs.
* Properties in those configs (e.g. ${key}) should be dynamically replaced
* Properties in those XML configs (e.g. ${key}) should be dynamically replaced
* with the corresponding value from our ConfigurationService
*/
@Test
@@ -61,17 +61,46 @@ public class DSpaceConfigurationBeanTest
assertNotNull("Bean returned null", bean);
assertNotNull("Bean.name() returned null", bean.getProperty());
// The name of the ServiceExample bean should be the SAME as the value of "serviceExample.bean.name" in
// configuration, as the spring-test-beans.xml uses ${serviceExample.bean.name} to set the name
assertEquals("Bean.name() does not match configuration", cfg.getProperty("testDynamicBean.property"),
// The bean's getProperty() method should return the same value as "testDynamicBean.property" in DSpace's
// configuration. This is cause bean's property is set to ${testDynamicBean.property} in spring-test-beans.xml
assertEquals("Bean.getProperty() does not match configuration", cfg.getProperty("testDynamicBean.property"),
bean.getProperty());
}
/**
* Test that property substitution is working properly in Spring PropertySource (e.g. @Value annotations)
* Properties in those annotations, e.g. @Value("${key}"), should be dynamically replaced with the corresponding
* value from our ConfigurationService
*/
@Test
public void testGetPropertySourceFromConfigurationService() {
// Load configs from files
ConfigurationService cfg = getKernel().getConfigurationService();
assertNotNull("ConfigurationService returned null", cfg);
assertNotNull("test config returned null", cfg.getProperty("testDynamicBean.property"));
// Load test bean which is defined by TestDynamicAnnotationConfiguration
TestDynamicPropertyBean bean = getKernel().getServiceManager().getServiceByName("propertyBeanUsingAnnotation",
TestDynamicPropertyBean.class);
// The Test bean's property should be automatically set (see TestDynamicAnnotationConfiguration)
String configValue = bean.getProperty();
assertNotNull("PropertySource config returned null", configValue);
// The value of "configValue" should be equal to "testDynamicBean.property" in our configuration.
// This is because configValue is set via an @Value annotation in TestDynamicAnnotationConfiguration
assertEquals("PropertySource config does not match configuration", cfg.getProperty("testDynamicBean.property"),
configValue);
}
/**
* Test that automatic reloading of configuration via bean settings also works.
*
* @TODO: This test does not actually work yet, because Commons Configuration v2 doesn't yet have a
* org.apache.commons.configuration2.spring.ConfigurationPropertiesFactoryBean that supports reloading properties.
* NOTE: This test also fails in Commons Configuration v1 (e.g. in DSpace 6.x). So, it's possible we may not be
* able to support reloadable properties via Spring beans (until Commons Configuration does)
*/
/*@Test
public void testReloadBeanSettingFromConfigurationService() throws ConfigurationException, InterruptedException {

View File

@@ -0,0 +1,33 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.servicemanager.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* A test bean which we will configure to load its one property via @Value annotation
* <P>
* See DSpaceConfigurationFactoryBeanTest.
*
* @author Tim Donohue
*/
@Configuration
public class TestDynamicAnnotationConfiguration {
// This setting should be loaded from the "testDynamicBean.property" configuration in local.properties
@Value("${testDynamicBean.property}")
private String value;
@Bean
public TestDynamicPropertyBean propertyBeanUsingAnnotation() {
TestDynamicPropertyBean bean = new TestDynamicPropertyBean();
bean.setProperty(value);
return bean;
}
}

View File

@@ -10,11 +10,18 @@
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!-- Place all test service bean definitions below here -->
<!-- Scan for annotated components in the specified test package(s). This allows tests using
@Configuration annotations, e.g. see org.dspace.servicemanager.config.TestDynamicAnnotationConfiguration -->
<context:component-scan base-package="org.dspace.servicemanager.config" />
<!-- sample cache bean -->
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager" ref="org.dspace.caching.ehcache.CacheManager"/>