diff --git a/spring-cloud-netflix-core/pom.xml b/spring-cloud-netflix-core/pom.xml index ad6a83d4..299ff474 100644 --- a/spring-cloud-netflix-core/pom.xml +++ b/spring-cloud-netflix-core/pom.xml @@ -1,6 +1,6 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 org.springframework.cloud @@ -29,6 +29,7 @@ org.springframework.boot spring-boot-autoconfigure + org.springframework.cloud spring-cloud-commons @@ -158,5 +159,15 @@ spring-boot-starter-test test + + org.springframework.boot + spring-boot-starter-data-jpa + test + + + com.h2database + h2 + test + diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/archaius/ArchaiusAutoConfiguration.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/archaius/ArchaiusAutoConfiguration.java index 72d2fde1..36ca5ef8 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/archaius/ArchaiusAutoConfiguration.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/archaius/ArchaiusAutoConfiguration.java @@ -17,6 +17,7 @@ package org.springframework.cloud.netflix.archaius; import java.lang.reflect.Field; +import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import javax.annotation.PreDestroy; @@ -28,6 +29,13 @@ import org.apache.commons.configuration.EnvironmentConfiguration; import org.apache.commons.configuration.SystemConfiguration; import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; +import com.netflix.config.ConcurrentCompositeConfiguration; +import com.netflix.config.ConfigurationManager; +import com.netflix.config.DynamicPropertyFactory; +import com.netflix.config.DynamicURLConfiguration; +import com.netflix.config.DeploymentContext; +import com.netflix.config.AggregatedConfiguration; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -40,12 +48,6 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.util.ReflectionUtils; -import com.netflix.config.ConcurrentCompositeConfiguration; -import com.netflix.config.ConfigurationManager; -import com.netflix.config.DynamicPropertyFactory; -import com.netflix.config.DynamicURLConfiguration; - -import static com.netflix.config.ConfigurationBasedDeploymentContext.DEPLOYMENT_APPLICATION_ID_PROPERTY; import static com.netflix.config.ConfigurationManager.APPLICATION_PROPERTIES; import static com.netflix.config.ConfigurationManager.DISABLE_DEFAULT_ENV_CONFIG; import static com.netflix.config.ConfigurationManager.DISABLE_DEFAULT_SYS_CONFIG; @@ -66,6 +68,9 @@ public class ArchaiusAutoConfiguration { @Autowired private ConfigurableEnvironment env; + @Autowired + private List externalConfigurations; + @PreDestroy public void close() { setStatic(ConfigurationManager.class, "instance", null); @@ -85,7 +90,7 @@ public class ArchaiusAutoConfiguration { @Configuration @ConditionalOnClass(Endpoint.class) - protected static class ArchaiusEndpointConfuguration { + protected static class ArchaiusEndpointConfiguration { @Bean protected ArchaiusEndpoint archaiusEndpoint() { return new ArchaiusEndpoint(); @@ -95,7 +100,8 @@ public class ArchaiusAutoConfiguration { @Configuration @ConditionalOnProperty(value = "archaius.propagate.environmentChangedEvent", matchIfMissing = true) @ConditionalOnClass(EnvironmentChangeEvent.class) - protected static class PropagateEventsConfiguration implements ApplicationListener { + protected static class PropagateEventsConfiguration implements + ApplicationListener { @Autowired private Environment env; @@ -109,14 +115,13 @@ public class ArchaiusAutoConfiguration { int type = AbstractConfiguration.EVENT_SET_PROPERTY; String value = env.getProperty(key); boolean beforeUpdate = false; - listener.configurationChanged(new ConfigurationEvent(source, - type, key, value, beforeUpdate)); + listener.configurationChanged(new ConfigurationEvent(source, type, + key, value, beforeUpdate)); } } } } - @SuppressWarnings("deprecation") protected void configureArchaius(ConfigurableEnvironmentConfiguration envConfig) { if (initialized.compareAndSet(false, true)) { String appName = this.env.getProperty("spring.application.name"); @@ -124,20 +129,17 @@ public class ArchaiusAutoConfiguration { appName = "application"; log.warn("No spring.application.name found, defaulting to 'application'"); } - // this is deprecated, but currently it seams the only way to set it initially - System.setProperty(DEPLOYMENT_APPLICATION_ID_PROPERTY, appName); - - // TODO: support for other DeploymentContexts + System.setProperty(DeploymentContext.ContextKey.appId.getKey(), appName); ConcurrentCompositeConfiguration config = new ConcurrentCompositeConfiguration(); // support to add other Configurations (Jdbc, DynamoDb, Zookeeper, jclouds, // etc...) - /* - * if (factories != null && !factories.isEmpty()) { for - * (PropertiesSourceFactory factory: factories) { - * config.addConfiguration(factory.getConfiguration(), factory.getName()); } } - */ + if (externalConfigurations != null) { + for (AbstractConfiguration externalConfig : externalConfigurations) { + config.addConfiguration(externalConfig); + } + } config.addConfiguration(envConfig, ConfigurableEnvironmentConfiguration.class.getSimpleName()); @@ -165,7 +167,7 @@ public class ArchaiusAutoConfiguration { config.setContainerConfigurationIndex(config .getIndexOfConfiguration(appOverrideConfig)); - ConfigurationManager.install(config); + addArchaiusConfiguration(config); } else { // TODO: reinstall ConfigurationManager @@ -173,6 +175,26 @@ public class ArchaiusAutoConfiguration { } } + private void addArchaiusConfiguration(ConcurrentCompositeConfiguration config) { + if (ConfigurationManager.isConfigurationInstalled()) { + AbstractConfiguration installedConfiguration = ConfigurationManager + .getConfigInstance(); + if (installedConfiguration instanceof ConcurrentCompositeConfiguration) { + ConcurrentCompositeConfiguration configInstance = (ConcurrentCompositeConfiguration) installedConfiguration; + configInstance.addConfiguration(config); + } + else { + installedConfiguration.append(config); + if (!(installedConfiguration instanceof AggregatedConfiguration)) { + log.warn("Appending a configuration to an existing non-aggregated installed configuration will have no effect"); + } + } + } + else { + ConfigurationManager.install(config); + } + } + private static void setStatic(Class type, String name, Object value) { // Hack a private static field Field field = ReflectionUtils.findField(type, name); diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/archaius/ArchaiusAutoConfigurationTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/archaius/ArchaiusAutoConfigurationTests.java index 2f269cca..6f896ee2 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/archaius/ArchaiusAutoConfigurationTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/archaius/ArchaiusAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2015 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. @@ -23,14 +23,17 @@ import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; import org.junit.After; import org.junit.Test; +import com.netflix.config.ConfigurationManager; +import com.netflix.config.DynamicPropertyFactory; +import com.netflix.config.DynamicStringProperty; + import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.cloud.context.environment.EnvironmentChangeEvent; import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import com.netflix.config.ConfigurationManager; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; /** * @author Dave Syer @@ -76,4 +79,37 @@ public class ArchaiusAutoConfigurationTests { assertEquals("my.newval", this.propertyValue); } + @Test + public void configurationWithoutExternalConfigurations() throws Exception { + this.context = new AnnotationConfigApplicationContext( + ArchaiusAutoConfiguration.class); + DynamicStringProperty dbProperty = DynamicPropertyFactory.getInstance() + .getStringProperty("db.property", null); + DynamicStringProperty staticProperty = DynamicPropertyFactory.getInstance() + .getStringProperty("archaius.file.property", null); + + assertNull(dbProperty.getValue()); + assertNotNull(staticProperty.getValue()); + assertEquals("Static config file property", staticProperty.getValue()); + } + + @Test + public void configurationWithInjectedDbConfiguration() throws Exception { + this.context = new AnnotationConfigApplicationContext( + ArchaiusAutoConfiguration.class, ArchaiusExternalConfiguration.class); + DynamicStringProperty dbProperty = DynamicPropertyFactory.getInstance() + .getStringProperty("db.property", null); + DynamicStringProperty secondDbProperty = DynamicPropertyFactory.getInstance() + .getStringProperty("db.second.property", null); + DynamicStringProperty staticProperty = DynamicPropertyFactory.getInstance() + .getStringProperty("archaius.file.property", null); + + assertNotNull(dbProperty.getValue()); + assertNotNull(secondDbProperty.getValue()); + assertNotNull(staticProperty.getValue()); + assertEquals("this is a db property", dbProperty.getValue()); + assertEquals("this is another db property", secondDbProperty.getValue()); + assertEquals("Static config file property", staticProperty.getValue()); + } + } diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/archaius/ArchaiusExternalConfiguration.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/archaius/ArchaiusExternalConfiguration.java new file mode 100644 index 00000000..6aec364d --- /dev/null +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/archaius/ArchaiusExternalConfiguration.java @@ -0,0 +1,58 @@ +/* + * Copyright 2013-2015 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.cloud.netflix.archaius; + +import com.netflix.config.DynamicConfiguration; +import com.netflix.config.FixedDelayPollingScheduler; +import com.netflix.config.PolledConfigurationSource; +import com.netflix.config.sources.JDBCConfigurationSource; +import org.apache.commons.configuration.AbstractConfiguration; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.datasource.SingleConnectionDataSource; + +/** + * @author Alexandru-George Burghelea + */ +@Configuration +public class ArchaiusExternalConfiguration { + + @Bean + @Qualifier("dynamicConfiguration") + public AbstractConfiguration createDynamicConfiguration() { + PolledConfigurationSource source = new JDBCConfigurationSource(initDataSource(), + "select distinct property_key, property_value from properties", + "property_key", "property_value"); + return new DynamicConfiguration(source, new FixedDelayPollingScheduler(0, 1000, false)); + } + + @Bean + @Qualifier("dataSource") + public SingleConnectionDataSource initDataSource() { + SingleConnectionDataSource dataSource = new SingleConnectionDataSource(); + dataSource.setDriverClassName("org.h2.Driver"); + dataSource + .setUrl("jdbc:h2:mem:test_archaius;AUTOCOMMIT=ON;DB_CLOSE_DELAY=-1;MODE=PostgreSQL;INIT=RUNSCRIPT FROM 'classpath:archaius_db_store.sql'"); + dataSource.setUsername("sa"); + dataSource.setPassword(""); + dataSource.setSuppressClose(true); + return dataSource; + } + +} diff --git a/spring-cloud-netflix-core/src/test/resources/archaius_db_store.sql b/spring-cloud-netflix-core/src/test/resources/archaius_db_store.sql new file mode 100644 index 00000000..6b914cb5 --- /dev/null +++ b/spring-cloud-netflix-core/src/test/resources/archaius_db_store.sql @@ -0,0 +1,8 @@ +create table if not exists properties ( + property_key VARCHAR(40) NOT NULL PRIMARY KEY, + property_value VARCHAR(255) NOT NULL, +); + +insert into properties(property_key, property_value) values ('db.property','this is a db property'); +insert into properties(property_key, property_value) values ('db.second.property','this is another db property'); + diff --git a/spring-cloud-netflix-core/src/test/resources/config.properties b/spring-cloud-netflix-core/src/test/resources/config.properties new file mode 100644 index 00000000..1e9c021f --- /dev/null +++ b/spring-cloud-netflix-core/src/test/resources/config.properties @@ -0,0 +1,2 @@ +archaius.file.property=Static config file property +db.second.property=It should be overridden