Skip to content

Commit

Permalink
Merge pull request #37 from motusllc/allow_duplicate_definitions
Browse files Browse the repository at this point in the history
Allow duplicate placeholder configs if desired
  • Loading branch information
andrewharmellaw committed Nov 16, 2015
2 parents f0be048 + 92891ba commit 5deb3c3
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public class ArchaiusBridgePropertyPlaceholderConfigurer extends BridgePropertyP
private transient int delayMillis = DEFAULT_DELAY;
private transient boolean ignoreResourceNotFound = false;
private transient boolean ignoreDeletesFromSource = true;
private transient boolean allowMultiplePlaceholders = false;

private final transient ArchaiusSpringPropertyPlaceholderSupport propertyPlaceholderSupport
= new ArchaiusSpringPropertyPlaceholderSupport();
Expand Down Expand Up @@ -78,6 +79,16 @@ public void setIgnoreDeletesFromSource(boolean ignoreDeletesFromSource) {
this.ignoreDeletesFromSource = ignoreDeletesFromSource;
}

/**
* Should the system allow duplicate beans and just read from the initial one?
* This helps in the case where you want to define beans in both a parent web application
* context and a servlet-specific context
*/
public void setAllowMultiplePlaceholders(boolean allowMultiplePlaceholders) {
this.allowMultiplePlaceholders = allowMultiplePlaceholders;
}


@Override
protected String resolvePlaceholder(String placeholder, Properties props, int systemPropertiesMode) {
return propertyPlaceholderSupport.resolvePlaceholder(placeholder, props, systemPropertiesMode);
Expand All @@ -101,7 +112,8 @@ public void setLocation(Resource location) {
@Override
public void setLocations(Resource[] locations) {
try {
Map parameterMap = propertyPlaceholderSupport.getParameterMap(delayMillis, initialDelayMillis, ignoreDeletesFromSource, ignoreResourceNotFound);
Map parameterMap = propertyPlaceholderSupport.getParameterMap(delayMillis, initialDelayMillis, ignoreDeletesFromSource,
ignoreResourceNotFound, allowMultiplePlaceholders);

// If there is not also a JDBC properties location to consider
if (jdbcConnectionDetailMap == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public class ArchaiusPropertyPlaceholderConfigurer extends PropertyPlaceholderCo
private transient int delayMillis = DEFAULT_DELAY;
private transient boolean ignoreResourceNotFound = false;
private transient boolean ignoreDeletesFromSource = true;
private transient boolean allowMultiplePlaceholders = false;

private final transient ArchaiusSpringPropertyPlaceholderSupport propertyPlaceholderSupport
= new ArchaiusSpringPropertyPlaceholderSupport();
Expand Down Expand Up @@ -72,6 +73,15 @@ public void setIgnoreDeletesFromSource(boolean ignoreDeletesFromSource) {
this.ignoreDeletesFromSource = ignoreDeletesFromSource;
}

/**
* Should the system allow duplicate beans and just read from the initial one?
* This helps in the case where you want to define beans in both a parent web application
* context and a servlet-specific context
*/
public void setAllowMultiplePlaceholders(boolean allowMultiplePlaceholders) {
this.allowMultiplePlaceholders = allowMultiplePlaceholders;
}

@Override
public void setIgnoreResourceNotFound(boolean setting) {
ignoreResourceNotFound = setting;
Expand Down Expand Up @@ -101,7 +111,8 @@ public void setLocation(Resource location) {
@Override
public void setLocations(Resource[] locations) {
try {
Map parameterMap = propertyPlaceholderSupport.getParameterMap(delayMillis, initialDelayMillis, ignoreDeletesFromSource, ignoreResourceNotFound);
Map parameterMap = propertyPlaceholderSupport.getParameterMap(delayMillis, initialDelayMillis, ignoreDeletesFromSource,
ignoreResourceNotFound, allowMultiplePlaceholders);

// If there is not also a JDBC properties location to consider
if (jdbcConnectionDetailMap == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ protected String resolvePlaceholder(String placeholder, Properties props, int sy
*/
protected void setLocations(Map<String, String> parameterMap, Resource[] locations) throws IOException {

ifHasExistingPropertiesSourceThenThrowIllegalStateException();

ConcurrentCompositeConfiguration config = addFileAndClasspathPropertyLocationsToConfiguration(parameterMap, locations);

DynamicPropertyFactory.initWithConfigurationSource(config);
ConcurrentCompositeConfiguration config = getExistingConfigIfAllowed(parameterMap);
if (config == null) {
config = addFileAndClasspathPropertyLocationsToConfiguration(parameterMap, locations);
DynamicPropertyFactory.initWithConfigurationSource(config);
}
}

/**
Expand All @@ -90,16 +90,16 @@ protected ConcurrentCompositeConfiguration setMixedResourcesAsPropertySources(
Resource[] locations,
Map<String, String> jdbcConnectionDetailMap) throws IOException {

ifHasExistingPropertiesSourceThenThrowIllegalStateException();

DynamicConfiguration dynamicConfiguration = buildDynamicConfigFromConnectionDetailsMap(jdbcConnectionDetailMap, parameterMap);
ConcurrentCompositeConfiguration conComConfiguration = new ConcurrentCompositeConfiguration();
conComConfiguration.addConfiguration(dynamicConfiguration);
conComConfiguration = addFileAndClasspathPropertyLocationsToConfiguration(conComConfiguration, parameterMap, locations);

DynamicPropertyFactory.initWithConfigurationSource(conComConfiguration);
ConcurrentCompositeConfiguration config = getExistingConfigIfAllowed(parameterMap);
if (config == null) {
DynamicConfiguration dynamicConfiguration = buildDynamicConfigFromConnectionDetailsMap(jdbcConnectionDetailMap, parameterMap);
config = new ConcurrentCompositeConfiguration();
config.addConfiguration(dynamicConfiguration);
config = addFileAndClasspathPropertyLocationsToConfiguration(config, parameterMap, locations);
DynamicPropertyFactory.initWithConfigurationSource(config);
}

return conComConfiguration;
return config;
}

private ConcurrentCompositeConfiguration addFileAndClasspathPropertyLocationsToConfiguration(
Expand Down Expand Up @@ -133,15 +133,35 @@ private ConcurrentCompositeConfiguration addFileAndClasspathPropertyLocationsToC

return conComConfiguration;
}

private ConcurrentCompositeConfiguration getExistingConfigIfAllowed(Map<String, String> parameterMap) {

boolean allowMultiplePlaceholders = Boolean.parseBoolean(parameterMap.get(JdbcContants.ALLOW_MULTIPLE_PLACEHOLDERS));

if (DynamicPropertyFactory.getBackingConfigurationSource() != null) {
if (allowMultiplePlaceholders) {
LOGGER.warn("Archaius is already configured with a property source/sources. Reusing those instead. ");
return (ConcurrentCompositeConfiguration) DynamicPropertyFactory.getBackingConfigurationSource();
} else {
LOGGER.error("There was already a config source (or sources) configured.");
throw new IllegalStateException("Archaius is already configured with a property source/sources.");
}
} else {
return null;
}
}

protected Map<String, String> getParameterMap(int delayMillis, int initialDelayMillis, boolean ignoreDeleteFromSource, boolean ignoreResourceNotFound) {
protected Map<String, String> getParameterMap(int delayMillis, int initialDelayMillis,
boolean ignoreDeleteFromSource, boolean ignoreResourceNotFound,
boolean allowMultiplePlaceholders) {

Map parameterMap = new HashMap();

parameterMap.put(JdbcContants.DELAY_MILLIS, String.valueOf(delayMillis));
parameterMap.put(JdbcContants.INITIAL_DELAY_MILLIS, String.valueOf(initialDelayMillis));
parameterMap.put(JdbcContants.IGNORE_DELETE_FROM_SOURCE, String.valueOf(ignoreDeleteFromSource));
parameterMap.put(JdbcContants.IGNORE_RESOURCE_NOT_FOUND, String.valueOf(ignoreResourceNotFound));
parameterMap.put(JdbcContants.ALLOW_MULTIPLE_PLACEHOLDERS, String.valueOf(allowMultiplePlaceholders));

return parameterMap;
}
Expand Down Expand Up @@ -180,13 +200,6 @@ private Map<String, String> createDatabaseKeyValueMap(String jdbcUri) {
return jdbcMap;
}

private void ifHasExistingPropertiesSourceThenThrowIllegalStateException() {
if (DynamicPropertyFactory.getBackingConfigurationSource() != null) {
LOGGER.error("There was already a config source (or sources) configured.");
throw new IllegalStateException("Archaius is already configured with a property source/sources.");
}
}

private DynamicConfiguration buildDynamicConfigFromConnectionDetailsMap(Map<String, String> jdbcConnectionDetailMap, Map<String, String> parameterMap) {

int initialDelayMillis = Integer.valueOf(parameterMap.get(JdbcContants.INITIAL_DELAY_MILLIS));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ private JdbcContants() {
public static final String IGNORE_DELETE_FROM_SOURCE = "ignoreDeletesFromSource";
public static final String INITIAL_DELAY_MILLIS = "initialDelayMillis";
public static final String DELAY_MILLIS = "delayMillis";
public static final String ALLOW_MULTIPLE_PLACEHOLDERS = "allowMultiplePlaceholders";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.capgemini.archaius.spring

import org.springframework.beans.factory.BeanCreationException
import org.springframework.context.support.ClassPathXmlApplicationContext
import org.springframework.test.context.ActiveProfiles
import spock.lang.Specification

/**
* @author: Scott Rankin
* @version: 1.0
*/
@ActiveProfiles('default')
class SpringDuplicateDefinitionIsNotOkSpec extends Specification {

def "missing spring properties files is not ok if IgnoreResourceNotFound property set to false" () {
when:
ctx = new ClassPathXmlApplicationContext('spring/springDuplicateDefinitionIsNotOkTest.xml')
then:
BeanCreationException bce = thrown()
bce.cause.message == 'Failed properties: Property \'locations\' threw exception; nested exception is ' +
'java.lang.IllegalStateException: Archaius is already configured with a property source/sources.'
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.capgemini.archaius.spring

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.ActiveProfiles
import spock.lang.Specification

/**
* @author: Scott Rankin
* @version: 1.0
*/
@ActiveProfiles('default')
@ContextConfiguration(locations = 'classpath:spring/springDuplicateDefinitionIsOkTest.xml')
class SpringDuplicateDefinitionIsOkSpec extends Specification {
@Autowired
@Qualifier('configOne')
private final ArchaiusPropertyPlaceholderConfigurer configOne

@Autowired
@Qualifier('configTwo')
private final ArchaiusPropertyPlaceholderConfigurer configTwo

def 'Duplicate definitions OK and config one loads properties' () {
expect:
configOne.resolvePlaceholder('var2', null, 0) == 'MY SECOND VAR'
}

def 'Duplicate definitions OK and config two does not load its specified properties' () {
expect:
configTwo.resolvePlaceholder('var3', null, 0) == null
}
}
2 changes: 1 addition & 1 deletion src/test/resources/META-INF/even-more-system.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var1=${mvn.var1}
var2=MY SECOND VAR (THIS ONE WINS)

var3=THIS IS THE THIRD

27 changes: 27 additions & 0 deletions src/test/resources/spring/springDuplicateDefinitionIsNotOkTest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

<!-- Config loading via Spring-Archaius-->
<bean class="com.capgemini.archaius.spring.ArchaiusPropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/META-INF/system.properties</value>
<value>classpath:/META-INF/even-more-system.properties</value>
</list>
</property>
</bean>

<bean class="com.capgemini.archaius.spring.ArchaiusPropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/META-INF/system.properties</value>
<value>classpath:/META-INF/even-more-system.properties</value>
</list>
</property>
</bean>

</beans>
29 changes: 29 additions & 0 deletions src/test/resources/spring/springDuplicateDefinitionIsOkTest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

<!-- Config loading via Spring-Archaius-->
<bean class="com.capgemini.archaius.spring.ArchaiusPropertyPlaceholderConfigurer"
id="configOne">
<property name="allowMultiplePlaceholders" value="true"/>
<property name="locations">
<list>
<value>classpath:/META-INF/system.properties</value>
</list>
</property>
</bean>

<bean class="com.capgemini.archaius.spring.ArchaiusPropertyPlaceholderConfigurer"
id="configTwo">
<property name="allowMultiplePlaceholders" value="true"/>
<property name="locations">
<list>
<value>classpath:/META-INF/even-more-system.properties</value>
</list>
</property>
</bean>

</beans>

0 comments on commit 5deb3c3

Please sign in to comment.