Merge branch 'master' into BAEL-16646-2

This commit is contained in:
Alessio Stalla
2019-10-24 13:20:08 +02:00
parent db85c8f275
commit c499158763
20506 changed files with 1643665 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
## Spring Cloud
This module contains modules about Spring Cloud
+70
View File
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung.spring.cloud</groupId>
<artifactId>spring-cloud</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>spring-cloud</name>
<packaging>pom</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<modules>
<module>spring-cloud-config</module>
<module>spring-cloud-eureka</module>
<module>spring-cloud-hystrix</module>
<module>spring-cloud-bootstrap</module>
<module>spring-cloud-ribbon-client</module>
<module>spring-cloud-rest</module>
<module>spring-cloud-zookeeper</module>
<module>spring-cloud-gateway</module>
<module>spring-cloud-stream</module>
<module>spring-cloud-stream-starters/twitterhdfs</module>
<module>spring-cloud-connectors-heroku</module>
<module>spring-cloud-aws</module>
<module>spring-cloud-consul</module>
<module>spring-cloud-zuul-eureka-integration</module>
<module>spring-cloud-contract</module>
<module>spring-cloud-kubernetes</module>
<module>spring-cloud-archaius</module>
<module>spring-cloud-functions</module>
<module>spring-cloud-vault</module>
<!-- <module>spring-cloud-security</module> --> <!-- Fixing in BAEL-10887 -->
<module>spring-cloud-task</module>
<module>spring-cloud-zuul</module>
<module>spring-cloud-zuul-fallback</module>
</modules>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot-maven-plugin.version}</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<properties>
<spring-session.version>1.2.2.RELEASE</spring-session.version>
<spring-cloud-dependencies.version>Brixton.SR7</spring-cloud-dependencies.version>
<spring-cloud-starter-config.version>1.2.2.RELEASE</spring-cloud-starter-config.version>
<spring-cloud-config-server.version>1.2.2.RELEASE</spring-cloud-config-server.version>
<spring-cloud-starter-eureka.version>2.0.2.RELEASE</spring-cloud-starter-eureka.version>
<spring-cloud-starter-feign.version>1.4.6.RELEASE</spring-cloud-starter-feign.version>
<spring-cloud-starter-hystrix.version>1.2.3.RELEASE</spring-cloud-starter-hystrix.version>
<spring-cloud-stream.version>1.3.0.RELEASE</spring-cloud-stream.version>
<spring-boot-starter-web.version>1.4.2.RELEASE</spring-boot-starter-web.version>
<spring-boot-maven-plugin.version>1.4.2.RELEASE</spring-boot-maven-plugin.version>
<spring-cloud-starter-zuul.version>1.2.3.RELEASE</spring-cloud-starter-zuul.version>
</properties>
</project>
@@ -0,0 +1,21 @@
# Spring Cloud Archaius
This module contains articles about Spring Cloud with Netflix Archaius
# Relevant Articles
- [Introduction to Netflix Archaius with Spring Cloud](https://www.baeldung.com/netflix-archaius-spring-cloud-integration)
- [Netflix Archaius with Various Database Configurations](https://www.baeldung.com/netflix-archaius-database-configurations)
#### Basic Config
This service has the basic, out-of-the-box Spring Cloud Netflix Archaius configuration.
#### Extra Configs
This service customizes some properties supported by Archaius.
These properties are set up on the main method, since Archaius uses System properties, but they could be added as command line arguments when launching the app.
#### Additional Sources
In this service we create a new AbstractConfiguration bean, setting up a new Configuration Properties source.
These properties have precedence over all the other properties in the Archaius Composite Configuration.
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>additional-sources-simple</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>additional-sources-simple</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung.spring.cloud</groupId>
<artifactId>spring-cloud-archaius</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,13 @@
package com.baeldung.spring.cloud.archaius.additionalsources;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AdditionalSourcesSimpleApplication {
public static void main(String[] args) {
SpringApplication.run(AdditionalSourcesSimpleApplication.class, args);
}
}
@@ -0,0 +1,26 @@
package com.baeldung.spring.cloud.archaius.additionalsources.config;
import java.io.IOException;
import java.net.URL;
import org.apache.commons.configuration.AbstractConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import com.netflix.config.DynamicConfiguration;
import com.netflix.config.FixedDelayPollingScheduler;
import com.netflix.config.PolledConfigurationSource;
import com.netflix.config.sources.URLConfigurationSource;
@Configuration
public class ApplicationPropertiesConfigurations {
@Bean
public AbstractConfiguration addApplicationPropertiesSource() throws IOException {
URL configPropertyURL = (new ClassPathResource("other-config.properties")).getURL();
PolledConfigurationSource source = new URLConfigurationSource(configPropertyURL);
return new DynamicConfiguration(source, new FixedDelayPollingScheduler());
}
}
@@ -0,0 +1,37 @@
package com.baeldung.spring.cloud.archaius.additionalsources.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.config.DynamicStringProperty;
@RestController
public class ConfigPropertiesController {
private DynamicStringProperty propertyOneWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.one", "not found!");
private DynamicStringProperty propertyTwoWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.two", "not found!");
private DynamicStringProperty propertyThreeWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.three", "not found!");
private DynamicStringProperty propertyFourWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.four", "not found!");
@GetMapping("/properties-from-dynamic")
public Map<String, String> getPropertiesFromDynamic() {
Map<String, String> properties = new HashMap<>();
properties.put(propertyOneWithDynamic.getName(), propertyOneWithDynamic.get());
properties.put(propertyTwoWithDynamic.getName(), propertyTwoWithDynamic.get());
properties.put(propertyThreeWithDynamic.getName(), propertyThreeWithDynamic.get());
properties.put(propertyFourWithDynamic.getName(), propertyFourWithDynamic.get());
return properties;
}
}
@@ -0,0 +1,3 @@
server.port=8082
baeldung.archaius.properties.one=one FROM:application.properties
baeldung.archaius.properties.two=two FROM:application.properties
@@ -0,0 +1,2 @@
baeldung.archaius.properties.one=one FROM:config.properties
baeldung.archaius.properties.three=three FROM:config.properties
@@ -0,0 +1,2 @@
baeldung.archaius.properties.one=one FROM:other-config.properties
baeldung.archaius.properties.four=four FROM:other-config.properties
@@ -0,0 +1,54 @@
package com.baeldung.spring.cloud.archaius.additionalsources;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ArchaiusAdditionalSourcesLiveTest {
private static final String BASE_URL = "http://localhost:8082";
private static final String DYNAMIC_PROPERTIES_URL = "/properties-from-dynamic";
private static final Map<String, String> EXPECTED_ARCHAIUS_PROPERTIES = createExpectedArchaiusProperties();
private static Map<String, String> createExpectedArchaiusProperties() {
Map<String, String> map = new HashMap<>();
map.put("baeldung.archaius.properties.one", "one FROM:other-config.properties");
map.put("baeldung.archaius.properties.two", "two FROM:application.properties");
map.put("baeldung.archaius.properties.three", "three FROM:config.properties");
map.put("baeldung.archaius.properties.four", "four FROM:other-config.properties");
return map;
}
@Autowired
ConfigurableApplicationContext context;
@Autowired
private TestRestTemplate template;
private <T> Map<T, T> exchangeAsMap(String uri, ParameterizedTypeReference<Map<T, T>> responseType) {
return template.exchange(uri, HttpMethod.GET, null, responseType)
.getBody();
}
@Test
public void givenNonDefaultConfigurationFilesSetup_whenRequestProperties_thenEndpointRetrievesValuesInFiles() {
Map<String, String> initialResponse = this.exchangeAsMap(BASE_URL + DYNAMIC_PROPERTIES_URL, new ParameterizedTypeReference<Map<String, String>>() {
});
assertThat(initialResponse).containsAllEntriesOf(EXPECTED_ARCHAIUS_PROPERTIES);
}
}
@@ -0,0 +1,15 @@
package com.baeldung.spring.cloud.archaius.additionalsources;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AdditionalSourcesSimpleApplication.class)
public class SpringContextIntegrationTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}
@@ -0,0 +1,15 @@
package com.baeldung.spring.cloud.archaius.additionalsources;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AdditionalSourcesSimpleApplication.class)
public class SpringContextTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>basic-config</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>basic-config</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung.spring.cloud</groupId>
<artifactId>spring-cloud-archaius</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,13 @@
package com.baeldung.spring.cloud.archaius.basic;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class BasicArchaiusApplication {
public static void main(String[] args) {
SpringApplication.run(BasicArchaiusApplication.class, args);
}
}
@@ -0,0 +1,70 @@
package com.baeldung.spring.cloud.archaius.basic.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.netflix.config.DynamicIntProperty;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.config.DynamicStringProperty;
@RestController
public class ConfigPropertiesController {
@Value("${baeldung.archaius.properties.one:not found!}")
private String propertyOneWithValue;
@Value("${baeldung.archaius.properties.two:not found!}")
private String propertyTwoWithValue;
@Value("${baeldung.archaius.properties.three:not found!}")
private String propertyThreeWithValue;
@Value("${baeldung.archaius.properties.four:not found!}")
private String propertyFourWithValue;
private DynamicStringProperty propertyOneWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.one", "not found!");
private DynamicStringProperty propertyTwoWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.two", "not found!");
private DynamicStringProperty propertyThreeWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.three", "not found!");
private DynamicStringProperty propertyFourWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.four", "not found!");
private DynamicIntProperty intPropertyWithDynamic = DynamicPropertyFactory.getInstance()
.getIntProperty("baeldung.archaius.properties.int", 0);
@GetMapping("/properties-from-value")
public Map<String, String> getPropertiesFromValue() {
Map<String, String> properties = new HashMap<>();
properties.put("baeldung.archaius.properties.one", propertyOneWithValue);
properties.put("baeldung.archaius.properties.two", propertyTwoWithValue);
properties.put("baeldung.archaius.properties.three", propertyThreeWithValue);
properties.put("baeldung.archaius.properties.four", propertyFourWithValue);
return properties;
}
@GetMapping("/properties-from-dynamic")
public Map<String, String> getPropertiesFromDynamic() {
Map<String, String> properties = new HashMap<>();
properties.put(propertyOneWithDynamic.getName(), propertyOneWithDynamic.get());
properties.put(propertyTwoWithDynamic.getName(), propertyTwoWithDynamic.get());
properties.put(propertyThreeWithDynamic.getName(), propertyThreeWithDynamic.get());
properties.put(propertyFourWithDynamic.getName(), propertyFourWithDynamic.get());
return properties;
}
@GetMapping("/int-property")
public Map<String, Integer> getIntPropertyFromDynamic() {
Map<String, Integer> properties = new HashMap<>();
properties.put(intPropertyWithDynamic.getName(), intPropertyWithDynamic.get());
return properties;
}
}
@@ -0,0 +1,3 @@
server.port=8080
baeldung.archaius.properties.one=one FROM:application.properties
baeldung.archaius.properties.two=two FROM:application.properties
@@ -0,0 +1,4 @@
baeldung.archaius.properties.one=one FROM:config.properties
baeldung.archaius.properties.three=three FROM:config.properties
baeldung.archaius.properties.int=1
@@ -0,0 +1,2 @@
baeldung.archaius.properties.one=one FROM:other.properties
baeldung.archaius.properties.four=four FROM:other.properties
@@ -0,0 +1,42 @@
package com.baeldung.spring.cloud.archaius.basic;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Collections;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.config.DynamicStringProperty;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ArchaiusBasicConfigurationIntegrationTest {
@Autowired
ConfigurableApplicationContext context;
private DynamicStringProperty testPropertyWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.test.properties.one", "not found!");
@Test
public void givenIntialPropertyValue_whenPropertyChanges_thenArchaiusRetrievesNewValue() {
String initialValue = testPropertyWithDynamic.get();
TestPropertyValues.of("baeldung.archaius.test.properties.one=new-value")
.applyTo(context);
context.publishEvent(new EnvironmentChangeEvent(Collections.singleton("baeldung.archaius.test.properties.one")));
String finalValue = testPropertyWithDynamic.get();
assertThat(initialValue).isEqualTo("test-one");
assertThat(finalValue).isEqualTo("new-value");
}
}
@@ -0,0 +1,74 @@
package com.baeldung.spring.cloud.archaius.basic;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ArchaiusBasicConfigurationLiveTest {
private static final String BASE_URL = "http://localhost:8080";
private static final String DYNAMIC_PROPERTIES_URL = "/properties-from-dynamic";
private static final Map<String, String> EXPECTED_ARCHAIUS_PROPERTIES = createExpectedArchaiusProperties();
private static Map<String, String> createExpectedArchaiusProperties() {
Map<String, String> map = new HashMap<>();
map.put("baeldung.archaius.properties.one", "one FROM:application.properties");
map.put("baeldung.archaius.properties.two", "two FROM:application.properties");
map.put("baeldung.archaius.properties.three", "three FROM:config.properties");
map.put("baeldung.archaius.properties.four", "not found!");
return map;
}
private static final String VALUE_PROPERTIES_URL = "/properties-from-value";
private static final Map<String, String> EXPECTED_VALUE_PROPERTIES = createExpectedValueProperties();
private static Map<String, String> createExpectedValueProperties() {
Map<String, String> map = new HashMap<>();
map.put("baeldung.archaius.properties.one", "one FROM:application.properties");
map.put("baeldung.archaius.properties.two", "two FROM:application.properties");
map.put("baeldung.archaius.properties.three", "not found!");
map.put("baeldung.archaius.properties.four", "not found!");
return map;
}
@Autowired
ConfigurableApplicationContext context;
@Autowired
private TestRestTemplate template;
private <T> Map<T, T> exchangeAsMap(String uri, ParameterizedTypeReference<Map<T, T>> responseType) {
return template.exchange(uri, HttpMethod.GET, null, responseType)
.getBody();
}
@Test
public void givenDefaultConfigurationSetup_whenRequestProperties_thenEndpointRetrievesValuesInFiles() {
Map<String, String> initialResponse = this.exchangeAsMap(BASE_URL + DYNAMIC_PROPERTIES_URL, new ParameterizedTypeReference<Map<String, String>>() {
});
assertThat(initialResponse).containsAllEntriesOf(EXPECTED_ARCHAIUS_PROPERTIES);
}
@Test
public void givenNonDefaultConfigurationFilesSetup_whenRequestSpringVisibleProperties_thenEndpointDoesntRetrieveArchaiusProperties() {
Map<String, String> initialResponse = this.exchangeAsMap(BASE_URL + VALUE_PROPERTIES_URL, new ParameterizedTypeReference<Map<String, String>>() {
});
assertThat(initialResponse).containsAllEntriesOf(EXPECTED_VALUE_PROPERTIES);
}
}
@@ -0,0 +1,16 @@
package com.baeldung.spring.cloud.archaius.basic;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringContextIntegrationTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}
@@ -0,0 +1,16 @@
package com.baeldung.spring.cloud.archaius.basic;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringContextTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}
@@ -0,0 +1,17 @@
package org.baeldung;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.baeldung.spring.cloud.archaius.basic.BasicArchaiusApplication;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = BasicArchaiusApplication.class)
public class SpringContextIntegrationTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}
@@ -0,0 +1,17 @@
package org.baeldung;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.baeldung.spring.cloud.archaius.basic.BasicArchaiusApplication;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = BasicArchaiusApplication.class)
public class SpringContextTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}
@@ -0,0 +1,3 @@
baeldung.archaius.test.properties.one=test-one
baeldung.archaius.test.properties.two=test-two
baeldung.archaius.test.properties.int=1
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>dynamodb-config</artifactId>
<name>dynamodb-config</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung.spring.cloud</groupId>
<artifactId>spring-cloud-archaius</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-dynamodb</artifactId>
<version>${aws.sdk.dynamo.version}</version>
</dependency>
<dependency>
<groupId>com.github.derjust</groupId>
<artifactId>spring-data-dynamodb</artifactId>
<version>${spring.dynamo.version}</version>
</dependency>
<dependency>
<groupId>com.netflix.archaius</groupId>
<artifactId>archaius-aws</artifactId>
<version>${archaius.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<properties>
<aws.sdk.dynamo.version>1.11.407</aws.sdk.dynamo.version>
<spring.dynamo.version>5.0.3</spring.dynamo.version>
<archaius.version>0.7.6</archaius.version>
</properties>
</project>
@@ -0,0 +1,12 @@
package com.baeldung.spring.cloud.archaius.dynamosources;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DynamoSourcesApplication {
public static void main(String[] args) {
SpringApplication.run(DynamoSourcesApplication.class, args);
}
}
@@ -0,0 +1,52 @@
package com.baeldung.spring.cloud.archaius.dynamosources.config;
import java.util.Arrays;
import org.apache.commons.configuration.AbstractConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.util.TableUtils;
import com.baeldung.spring.cloud.archaius.dynamosources.dynamodb.ArchaiusProperties;
import com.baeldung.spring.cloud.archaius.dynamosources.dynamodb.ArchaiusPropertiesRepository;
import com.netflix.config.DynamicConfiguration;
import com.netflix.config.FixedDelayPollingScheduler;
import com.netflix.config.PolledConfigurationSource;
import com.netflix.config.sources.DynamoDbConfigurationSource;
@Configuration
public class ApplicationPropertiesConfigurations {
@Autowired
AmazonDynamoDB amazonDynamoDb;
@Autowired
private ArchaiusPropertiesRepository repository;
@Bean
public AbstractConfiguration addApplicationPropertiesSource() {
// Normally, the DB Table would be already created and populated.
// In this case, we'll do it just before creating the archaius config source that uses it
initDatabase();
PolledConfigurationSource source = new DynamoDbConfigurationSource(amazonDynamoDb);
return new DynamicConfiguration(source, new FixedDelayPollingScheduler());
}
private void initDatabase() {
// Create the table
DynamoDBMapper mapper = new DynamoDBMapper(amazonDynamoDb);
CreateTableRequest tableRequest = mapper.generateCreateTableRequest(ArchaiusProperties.class);
tableRequest.setProvisionedThroughput(new ProvisionedThroughput(1L, 1L));
TableUtils.createTableIfNotExists(amazonDynamoDb, tableRequest);
// Populate the table
ArchaiusProperties property = new ArchaiusProperties("baeldung.archaius.properties.one", "one FROM:dynamoDB");
ArchaiusProperties property3 = new ArchaiusProperties("baeldung.archaius.properties.three", "three FROM:dynamoDB");
repository.saveAll(Arrays.asList(property, property3));
}
}
@@ -0,0 +1,46 @@
package com.baeldung.spring.cloud.archaius.dynamosources.config;
import org.socialsignin.spring.data.dynamodb.repository.config.EnableDynamoDBRepositories;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder.EndpointConfiguration;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
@Configuration
@EnableDynamoDBRepositories(basePackages = "com.baeldung.spring.cloud.archaius.dynamosources.dynamodb")
public class DynamoDbConfiguration {
@Value("${amazon.dynamodb.endpoint}")
private String amazonDynamoDBEndpoint;
@Value("${aws.accessKeyId}")
private String amazonDynamoDBAccessKeyId;
@Value("${aws.secretKey}")
private String amazonDynamoDBSecretKey;
@Bean
public AmazonDynamoDB amazonDynamoDB() {
AmazonDynamoDB amazonDynamoDB = AmazonDynamoDBClientBuilder.standard()
.withCredentials(amazonAWSCredentials())
.withEndpointConfiguration(setupEndpointConfiguration())
.build();
return amazonDynamoDB;
}
private AWSCredentialsProvider amazonAWSCredentials() {
return new AWSStaticCredentialsProvider(new BasicAWSCredentials(amazonDynamoDBAccessKeyId, amazonDynamoDBSecretKey));
}
private EndpointConfiguration setupEndpointConfiguration() {
return new EndpointConfiguration(amazonDynamoDBEndpoint, Regions.DEFAULT_REGION.getName());
}
}
@@ -0,0 +1,32 @@
package com.baeldung.spring.cloud.archaius.dynamosources.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.config.DynamicStringProperty;
@RestController
public class ConfigPropertiesController {
private DynamicStringProperty propertyOneWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.one", "not found!");
private DynamicStringProperty propertyTwoWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.two", "not found!");
private DynamicStringProperty propertyThreeWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.three", "not found!");
@GetMapping("/properties-from-dynamic")
public Map<String, String> getPropertiesFromDynamic() {
Map<String, String> properties = new HashMap<>();
properties.put(propertyOneWithDynamic.getName(), propertyOneWithDynamic.get());
properties.put(propertyTwoWithDynamic.getName(), propertyTwoWithDynamic.get());
properties.put(propertyThreeWithDynamic.getName(), propertyThreeWithDynamic.get());
return properties;
}
}
@@ -0,0 +1,23 @@
package com.baeldung.spring.cloud.archaius.dynamosources.dynamodb;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@DynamoDBTable(tableName = "archaiusProperties")
public class ArchaiusProperties {
@DynamoDBHashKey
@DynamoDBAttribute
private String key;
@DynamoDBAttribute
private String value;
}
@@ -0,0 +1,7 @@
package com.baeldung.spring.cloud.archaius.dynamosources.dynamodb;
import org.springframework.data.repository.CrudRepository;
public interface ArchaiusPropertiesRepository extends CrudRepository<ArchaiusProperties, String> {
}
@@ -0,0 +1,6 @@
server.port=8082
baeldung.archaius.properties.one=one FROM:application.properties
baeldung.archaius.properties.two=two FROM:application.properties
amazon.dynamodb.endpoint=http://localhost:8000/
aws.accessKeyId=key
aws.secretKey=key2
@@ -0,0 +1,53 @@
package com.baeldung.spring.cloud.archaius.dynamosources;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ArchaiusDynamoDbLiveTest {
private static final String BASE_URL = "http://localhost:8082";
private static final String DYNAMIC_PROPERTIES_URL = "/properties-from-dynamic";
private static final Map<String, String> EXPECTED_ARCHAIUS_PROPERTIES = createExpectedArchaiusProperties();
private static Map<String, String> createExpectedArchaiusProperties() {
Map<String, String> map = new HashMap<>();
map.put("baeldung.archaius.properties.one", "one FROM:dynamoDB");
map.put("baeldung.archaius.properties.two", "two FROM:application.properties");
map.put("baeldung.archaius.properties.three", "three FROM:dynamoDB");
return map;
}
@Autowired
ConfigurableApplicationContext context;
@Autowired
private TestRestTemplate template;
private <T> Map<T, T> exchangeAsMap(String uri, ParameterizedTypeReference<Map<T, T>> responseType) {
return template.exchange(uri, HttpMethod.GET, null, responseType)
.getBody();
}
@Test
public void givenNonDefaultConfigurationFilesSetup_whenRequestProperties_thenEndpointRetrievesValuesInFiles() {
Map<String, String> initialResponse = this.exchangeAsMap(BASE_URL + DYNAMIC_PROPERTIES_URL, new ParameterizedTypeReference<Map<String, String>>() {
});
assertThat(initialResponse).containsAllEntriesOf(EXPECTED_ARCHAIUS_PROPERTIES);
}
}
@@ -0,0 +1,20 @@
package com.baeldung.spring.cloud.archaius.dynamosources;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* To run this Live Test we need to:
* * start a dynamodb instance locally on port 8000(e.g. with the following command `docker run -p 8000:8000 --name bael-dynamodb amazon/dynamodb-local`)
*
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DynamoSourcesApplication.class)
public class SpringContextLiveTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>extra-configs</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>extra-configs</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung.spring.cloud</groupId>
<artifactId>spring-cloud-archaius</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-archaius</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>${spring-cloud-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<properties>
<spring-cloud-dependencies.version>2.0.1.RELEASE</spring-cloud-dependencies.version>
</properties>
</project>
@@ -0,0 +1,16 @@
package com.baeldung.spring.cloud.archaius.extraconfigs;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ExtraConfigsApplication {
public static void main(String[] args) {
// System properties can be set as command line arguments too
System.setProperty("archaius.configurationSource.additionalUrls", "classpath:other-config-dir/extra.properties");
System.setProperty("archaius.configurationSource.defaultFileName", "other.properties");
SpringApplication.run(ExtraConfigsApplication.class, args);
}
}
@@ -0,0 +1,60 @@
package com.baeldung.spring.cloud.archaius.extraconfigs.controllers;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.config.DynamicStringProperty;
@RestController
public class ConfigPropertiesController {
@Value("${baeldung.archaius.properties.one:not found!}")
private String propertyOneWithValue;
@Value("${baeldung.archaius.properties.two:not found!}")
private String propertyTwoWithValue;
@Value("${baeldung.archaius.properties.three:not found!}")
private String propertyThreeWithValue;
@Value("${baeldung.archaius.properties.four:not found!}")
private String propertyFourWithValue;
private DynamicStringProperty propertyOneWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.one", "not found!");
private DynamicStringProperty propertyTwoWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.two", "not found!");
private DynamicStringProperty propertyThreeWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.three", "not found!");
private DynamicStringProperty propertyFourWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.four", "not found!");
@GetMapping("/properties-from-value")
public Map<String, String> getPropertiesFromValue() {
Map<String, String> properties = new HashMap<>();
properties.put("baeldung.archaius.properties.one", propertyOneWithValue);
properties.put("baeldung.archaius.properties.two", propertyTwoWithValue);
properties.put("baeldung.archaius.properties.three", propertyThreeWithValue);
properties.put("baeldung.archaius.properties.four", propertyFourWithValue);
return properties;
}
@GetMapping("/properties-from-dynamic")
public Map<String, String> getPropertiesFromDynamic() {
Map<String, String> properties = new HashMap<>();
properties.put("baeldung.archaius.properties.one", propertyOneWithDynamic.get());
properties.put("baeldung.archaius.properties.two", propertyTwoWithDynamic.get());
properties.put("baeldung.archaius.properties.three", propertyThreeWithDynamic.get());
properties.put("baeldung.archaius.properties.four", propertyFourWithDynamic.get());
return properties;
}
}
@@ -0,0 +1,3 @@
server.port=8081
baeldung.archaius.properties.one=one FROM:application.properties
baeldung.archaius.properties.two=two FROM:application.properties
@@ -0,0 +1,2 @@
baeldung.archaius.properties.one=one FROM:extra.properties
baeldung.archaius.properties.three=three FROM:extra.properties
@@ -0,0 +1,2 @@
baeldung.archaius.properties.one=one FROM:other.properties
baeldung.archaius.properties.four=four FROM:other.properties
@@ -0,0 +1,54 @@
package com.baeldung.spring.cloud.archaius.extraconfigs;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ArchaiusExtraConfigsLiveTest {
private static final String BASE_URL = "http://localhost:8081";
private static final String DYNAMIC_PROPERTIES_URL = "/properties-from-dynamic";
private static final Map<String, String> EXPECTED_ARCHAIUS_PROPERTIES = createExpectedArchaiusProperties();
private static Map<String, String> createExpectedArchaiusProperties() {
Map<String, String> map = new HashMap<>();
map.put("baeldung.archaius.properties.one", "one FROM:application.properties");
map.put("baeldung.archaius.properties.two", "two FROM:application.properties");
map.put("baeldung.archaius.properties.three", "three FROM:extra.properties");
map.put("baeldung.archaius.properties.four", "four FROM:other.properties");
return map;
}
@Autowired
ConfigurableApplicationContext context;
@Autowired
private TestRestTemplate template;
private <T> Map<T, T> exchangeAsMap(String uri, ParameterizedTypeReference<Map<T, T>> responseType) {
return template.exchange(uri, HttpMethod.GET, null, responseType)
.getBody();
}
@Test
public void givenNonDefaultConfigurationFilesSetup_whenRequestProperties_thenEndpointRetrievesValuesInFiles() {
Map<String, String> initialResponse = this.exchangeAsMap(BASE_URL + DYNAMIC_PROPERTIES_URL, new ParameterizedTypeReference<Map<String, String>>() {
});
assertThat(initialResponse).containsAllEntriesOf(EXPECTED_ARCHAIUS_PROPERTIES);
}
}
@@ -0,0 +1,17 @@
package org.baeldung;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.baeldung.spring.cloud.archaius.extraconfigs.ExtraConfigsApplication;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ExtraConfigsApplication.class)
public class SpringContextIntegrationTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}
@@ -0,0 +1,17 @@
package org.baeldung;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.baeldung.spring.cloud.archaius.extraconfigs.ExtraConfigsApplication;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ExtraConfigsApplication.class)
public class SpringContextTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>jdbc-config</artifactId>
<name>jdbc-config</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung.spring.cloud</groupId>
<artifactId>spring-cloud-archaius</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,13 @@
package com.baeldung.spring.cloud.archaius.jdbconfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class JdbcSourcesApplication {
public static void main(String[] args) {
SpringApplication.run(JdbcSourcesApplication.class, args);
}
}
@@ -0,0 +1,27 @@
package com.baeldung.spring.cloud.archaius.jdbconfig.config;
import javax.sql.DataSource;
import org.apache.commons.configuration.AbstractConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.netflix.config.DynamicConfiguration;
import com.netflix.config.FixedDelayPollingScheduler;
import com.netflix.config.PolledConfigurationSource;
import com.netflix.config.sources.JDBCConfigurationSource;
@Configuration
public class ApplicationPropertiesConfigurations {
@Autowired
DataSource h2DataSource;
@Bean
public AbstractConfiguration addApplicationPropertiesSource() {
PolledConfigurationSource source = new JDBCConfigurationSource(h2DataSource, "select distinct key, value from properties", "key", "value");
return new DynamicConfiguration(source, new FixedDelayPollingScheduler());
}
}
@@ -0,0 +1,32 @@
package com.baeldung.spring.cloud.archaius.jdbconfig.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.config.DynamicStringProperty;
@RestController
public class ConfigPropertiesController {
private DynamicStringProperty propertyOneWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.one", "not found!");
private DynamicStringProperty propertyTwoWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.two", "not found!");
private DynamicStringProperty propertyThreeWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.three", "not found!");
@GetMapping("/properties-from-dynamic")
public Map<String, String> getPropertiesFromDynamic() {
Map<String, String> properties = new HashMap<>();
properties.put(propertyOneWithDynamic.getName(), propertyOneWithDynamic.get());
properties.put(propertyTwoWithDynamic.getName(), propertyTwoWithDynamic.get());
properties.put(propertyThreeWithDynamic.getName(), propertyThreeWithDynamic.get());
return properties;
}
}
@@ -0,0 +1,14 @@
package com.baeldung.spring.cloud.archaius.jdbconfig.jdbc;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Properties {
@Id
private String key;
@SuppressWarnings("unused")
private String value;
}
@@ -0,0 +1,4 @@
server.port=8082
baeldung.archaius.properties.one=one FROM:application.properties
baeldung.archaius.properties.two=two FROM:application.properties
spring.h2.console.enabled=true
@@ -0,0 +1,5 @@
insert into properties
values('baeldung.archaius.properties.one', 'one FROM:jdbc_source');
insert into properties
values('baeldung.archaius.properties.three', 'three FROM:jdbc_source');
@@ -0,0 +1,53 @@
package com.baeldung.spring.cloud.archaius.jdbconfig;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ArchaiusJDBCSourceLiveTest {
private static final String BASE_URL = "http://localhost:8082";
private static final String DYNAMIC_PROPERTIES_URL = "/properties-from-dynamic";
private static final Map<String, String> EXPECTED_ARCHAIUS_PROPERTIES = createExpectedArchaiusProperties();
private static Map<String, String> createExpectedArchaiusProperties() {
Map<String, String> map = new HashMap<>();
map.put("baeldung.archaius.properties.one", "one FROM:jdbc_source");
map.put("baeldung.archaius.properties.two", "two FROM:application.properties");
map.put("baeldung.archaius.properties.three", "three FROM:jdbc_source");
return map;
}
@Autowired
ConfigurableApplicationContext context;
@Autowired
private TestRestTemplate template;
private <T> Map<T, T> exchangeAsMap(String uri, ParameterizedTypeReference<Map<T, T>> responseType) {
return template.exchange(uri, HttpMethod.GET, null, responseType)
.getBody();
}
@Test
public void givenNonDefaultConfigurationFilesSetup_whenRequestProperties_thenEndpointRetrievesValuesInFiles() {
Map<String, String> initialResponse = this.exchangeAsMap(BASE_URL + DYNAMIC_PROPERTIES_URL, new ParameterizedTypeReference<Map<String, String>>() {
});
assertThat(initialResponse).containsAllEntriesOf(EXPECTED_ARCHAIUS_PROPERTIES);
}
}
@@ -0,0 +1,15 @@
package com.baeldung.spring.cloud.archaius.jdbconfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = JdbcSourcesApplication.class)
public class SpringContextIntegrationTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}
@@ -0,0 +1,15 @@
package com.baeldung.spring.cloud.archaius.jdbconfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = JdbcSourcesApplication.class)
public class SpringContextTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung.spring.cloud</groupId>
<artifactId>spring-cloud-archaius</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>spring-cloud-archaius</name>
<description>Spring Cloud Archaius Pom parent</description>
<packaging>pom</packaging>
<parent>
<groupId>com.baeldung.spring.cloud</groupId>
<artifactId>spring-cloud</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<modules>
<module>basic-config</module>
<module>additional-sources-simple</module>
<module>extra-configs</module>
<module>jdbc-config</module>
<module>dynamodb-config</module>
<module>zookeeper-config</module>
</modules>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-archaius</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<version>${junit.platform.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>${spring-cloud-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<properties>
<spring-cloud-dependencies.version>2.0.1.RELEASE</spring-cloud-dependencies.version>
<junit.platform.version>1.2.0</junit.platform.version>
</properties>
</project>
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>zookeeper-config</artifactId>
<name>zookeeper-config</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung.spring.cloud</groupId>
<artifactId>spring-cloud-archaius</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-config</artifactId>
<version>${cloud.zookeeper.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>${zookeeper.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<properties>
<cloud.zookeeper.version>2.0.0.RELEASE</cloud.zookeeper.version>
<zookeeper.version>3.4.13</zookeeper.version>
</properties>
</project>
@@ -0,0 +1,12 @@
package com.baeldung.spring.cloud.archaius.zookeeperconfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ZookeeperConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ZookeeperConfigApplication.class, args);
}
}
@@ -0,0 +1,58 @@
package com.baeldung.spring.cloud.archaius.zookeeperconfig.config;
import org.apache.curator.framework.CuratorFramework;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
/**
*
* Ideally, we wouldn't need to initialize the zookeeper config values.
* Here we do it to verify that configurations are being retrieved.
*
*/
@Component
public class ZookeeperConfigsInitializer {
private static final String CONFIG_BASE_NODE_PATH = "/config";
private static final String APPLICATION_BASE_NODE_PATH = CONFIG_BASE_NODE_PATH + "/application";
@Autowired
CuratorFramework client;
@EventListener
public void appReady(ApplicationReadyEvent event) throws Exception {
String pathOne = APPLICATION_BASE_NODE_PATH + "/baeldung.archaius.properties.one";
String valueOne = "one FROM:zookeeper";
String pathThree = APPLICATION_BASE_NODE_PATH + "/baeldung.archaius.properties.three";
String valueThree = "three FROM:zookeeper";
createBaseNodes();
setValue(pathOne, valueOne);
setValue(pathThree, valueThree);
}
private void setValue(String path, String value) throws Exception {
if (client.checkExists()
.forPath(path) == null) {
client.create()
.forPath(path, value.getBytes());
} else {
client.setData()
.forPath(path, value.getBytes());
}
}
private void createBaseNodes() throws Exception {
if (client.checkExists()
.forPath(CONFIG_BASE_NODE_PATH) == null) {
client.create()
.forPath(CONFIG_BASE_NODE_PATH);
}
if (client.checkExists()
.forPath(APPLICATION_BASE_NODE_PATH) == null) {
client.create()
.forPath(APPLICATION_BASE_NODE_PATH);
}
}
}
@@ -0,0 +1,51 @@
package com.baeldung.spring.cloud.archaius.zookeeperconfig.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.config.DynamicStringProperty;
@RestController
public class ConfigPropertiesController {
@Value("${baeldung.archaius.properties.one:not found!}")
private String propertyOneWithValue;
@Value("${baeldung.archaius.properties.two:not found!}")
private String propertyTwoWithValue;
@Value("${baeldung.archaius.properties.three:not found!}")
private String propertyThreeWithValue;
private DynamicStringProperty propertyOneWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.one", "not found!");
private DynamicStringProperty propertyTwoWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.two", "not found!");
private DynamicStringProperty propertyThreeWithDynamic = DynamicPropertyFactory.getInstance()
.getStringProperty("baeldung.archaius.properties.three", "not found!");
@GetMapping("/properties-from-dynamic")
public Map<String, String> getPropertiesFromDynamic() {
Map<String, String> properties = new HashMap<>();
properties.put(propertyOneWithDynamic.getName(), propertyOneWithDynamic.get());
properties.put(propertyTwoWithDynamic.getName(), propertyTwoWithDynamic.get());
properties.put(propertyThreeWithDynamic.getName(), propertyThreeWithDynamic.get());
return properties;
}
@GetMapping("/properties-from-value")
public Map<String, String> getPropertiesFromValue() {
Map<String, String> properties = new HashMap<>();
properties.put("baeldung.archaius.properties.one", propertyOneWithValue);
properties.put("baeldung.archaius.properties.two", propertyTwoWithValue);
properties.put("baeldung.archaius.properties.three", propertyThreeWithValue);
return properties;
}
}
@@ -0,0 +1,4 @@
server.port=8082
baeldung.archaius.properties.one=one FROM:application.properties
baeldung.archaius.properties.two=two FROM:application.properties
spring.application.name=zookeeper-config
@@ -0,0 +1,53 @@
package com.baeldung.spring.cloud.archaius.zookeeperconfig;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ArchaiusZookeeperLiveTest {
private static final String BASE_URL = "http://localhost:8082";
private static final String DYNAMIC_PROPERTIES_URL = "/properties-from-dynamic";
private static final Map<String, String> EXPECTED_ARCHAIUS_PROPERTIES = createExpectedArchaiusProperties();
private static Map<String, String> createExpectedArchaiusProperties() {
Map<String, String> map = new HashMap<>();
map.put("baeldung.archaius.properties.one", "one FROM:zookeeper");
map.put("baeldung.archaius.properties.two", "two FROM:application.properties");
map.put("baeldung.archaius.properties.three", "three FROM:zookeeper");
return map;
}
@Autowired
ConfigurableApplicationContext context;
@Autowired
private TestRestTemplate template;
private <T> Map<T, T> exchangeAsMap(String uri, ParameterizedTypeReference<Map<T, T>> responseType) {
return template.exchange(uri, HttpMethod.GET, null, responseType)
.getBody();
}
@Test
public void givenNonDefaultConfigurationFilesSetup_whenRequestProperties_thenEndpointRetrievesValuesInFiles() {
Map<String, String> initialResponse = this.exchangeAsMap(BASE_URL + DYNAMIC_PROPERTIES_URL, new ParameterizedTypeReference<Map<String, String>>() {
});
assertThat(initialResponse).containsAllEntriesOf(EXPECTED_ARCHAIUS_PROPERTIES);
}
}
@@ -0,0 +1,20 @@
package com.baeldung.spring.cloud.archaius.zookeeperconfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* This Live tTest requires:
* * A Zookeeper instance running locally on port 2181 (e.g. using `docker run --name bael-zookeeper -p 2181:2181 --restart always zookeeper`)
*
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ZookeeperConfigApplication.class)
public class SpringContextLiveTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}
+33
View File
@@ -0,0 +1,33 @@
# Spring Cloud AWS
# Relevant Articles
- [Spring Cloud AWS S3](https://www.baeldung.com/spring-cloud-aws-s3)
- [Spring Cloud AWS EC2](https://www.baeldung.com/spring-cloud-aws-ec2)
- [Spring Cloud AWS RDS](https://www.baeldung.com/spring-cloud-aws-rds)
- [Spring Cloud AWS Messaging Support](https://www.baeldung.com/spring-cloud-aws-messaging)
- [Instance Profile Credentials using Spring Cloud](http://www.baeldung.com/spring-cloud-instance-profiles)
#### Running the Integration Tests
To run the Live Tests, we need to have an AWS account and have API keys generated for programmatic access. Edit
the `application.properties` file to add the following properties:
```
cloud.aws.credentials.accessKey=YourAccessKey
cloud.aws.credentials.secretKey=YourSecretKey
cloud.aws.region.static=us-east-1
```
To test automatic DataSource creation from RDS instance, we also need to create an RDS instance in the AWS account.
Let's say that the RDS instance is called `spring-cloud-test-db` having the master password `se3retpass`, then we need
to write the following in `application.properties`:
```
cloud.aws.rds.spring-cloud-test-db
cloud.aws.rds.spring-cloud-test-db.password=se3retpass
```
Multiple application classes are available under this project. To launch InstanceProfileAwsApplication application, replace `start-class` under `pom.xml`:
```
<start-class>com.baeldung.spring.cloud.aws.InstanceProfileAwsApplication</start-class>
```
+64
View File
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung.spring.cloud</groupId>
<artifactId>spring-cloud-aws</artifactId>
<name>spring-cloud-aws</name>
<description>Spring Cloud AWS Examples</description>
<packaging>jar</packaging>
<parent>
<artifactId>parent-boot-1</artifactId>
<groupId>com.baeldung</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-1</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-aws</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-aws-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-aws-messaging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-aws</artifactId>
<version>2.0.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<properties>
<start-class>com.baeldung.spring.cloud.aws.SpringCloudAwsApplication</start-class>
<spring-cloud.version>Dalston.SR4</spring-cloud.version>
</properties>
</project>
@@ -0,0 +1,60 @@
package com.baeldung.spring.cloud.aws;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.baeldung.spring.cloud.aws.s3.SpringCloudS3Service;
@Configuration
@EnableAutoConfiguration
@ComponentScan("com.baeldung.spring.cloud.aws.s3")
public class InstanceProfileAwsApplication {
private static final Logger logger = LoggerFactory.getLogger(InstanceProfileAwsApplication.class);
private static final String applicationConfig = "spring.config.name:application-instance-profile";
private static String bucketName;
private static String fileName = "sample-file.txt";
private static void setupResources() {
bucketName = "baeldung-test-" + UUID.randomUUID()
.toString();
try {
Files.write(Paths.get(fileName), "Hello World!".getBytes());
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
public static void main(String[] args) {
setupResources();
if (!new File(fileName).exists()) {
logger.warn("Not able to create {} file. Check your folder permissions.", fileName);
System.exit(1);
}
SpringApplication application = new SpringApplicationBuilder(InstanceProfileAwsApplication.class).properties(applicationConfig)
.build();
ConfigurableApplicationContext context = application.run(args);
SpringCloudS3Service service = context.getBean(SpringCloudS3Service.class);
// S3 bucket operations
service.createBucket(bucketName);
service.uploadObject(bucketName, fileName);
service.downloadObject(bucketName, fileName);
service.deleteBucket(bucketName);
}
}
@@ -0,0 +1,14 @@
package com.baeldung.spring.cloud.aws;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;
@SpringBootApplication
@ImportResource("classpath:aws-config.xml")
public class SpringCloudAwsApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudAwsApplication.class, args);
}
}
@@ -0,0 +1,22 @@
package com.baeldung.spring.cloud.aws.config;
import com.amazonaws.services.sns.AmazonSNS;
import com.amazonaws.services.sqs.AmazonSQSAsync;
import org.springframework.cloud.aws.messaging.core.NotificationMessagingTemplate;
import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringCloudAwsConfig {
@Bean
public QueueMessagingTemplate queueMessagingTemplate(AmazonSQSAsync amazonSQSAsync) {
return new QueueMessagingTemplate(amazonSQSAsync);
}
@Bean
public NotificationMessagingTemplate notificationMessagingTemplate(AmazonSNS amazonSNS) {
return new NotificationMessagingTemplate(amazonSNS);
}
}
@@ -0,0 +1,9 @@
package com.baeldung.spring.cloud.aws.ec2;
import org.springframework.cloud.aws.context.config.annotation.EnableContextInstanceData;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableContextInstanceData
public class EC2EnableMetadata {
}
@@ -0,0 +1,62 @@
package com.baeldung.spring.cloud.aws.ec2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@Lazy
@Component
public class EC2Metadata {
@Value("${ami-id:N/A}")
private String amiId;
@Value("${hostname:N/A}")
private String hostname;
@Value("${instance-type:N/A}")
private String instanceType;
@Value("${services/domain:N/A}")
private String serviceDomain;
@Value("#{instanceData['Name'] ?: 'N/A'}")
private String name;
public String getAmiId() {
return amiId;
}
public String getHostname() {
return hostname;
}
public String getInstanceType() {
return instanceType;
}
public String getServiceDomain() {
return serviceDomain;
}
public String getName() {
return name;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("EC2Metadata [amiId=");
builder.append(amiId);
builder.append(", hostname=");
builder.append(hostname);
builder.append(", instanceType=");
builder.append(instanceType);
builder.append(", serviceDomain=");
builder.append(serviceDomain);
builder.append(", name=");
builder.append(name);
builder.append("]");
return builder.toString();
}
}
@@ -0,0 +1,52 @@
package com.baeldung.spring.cloud.aws.s3;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.WritableResource;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
@Component
public class SpringCloudS3 {
@Autowired
ResourceLoader resourceLoader;
@Autowired
ResourcePatternResolver resourcePatternResolver;
public void downloadS3Object(String s3Url) throws IOException {
Resource resource = resourceLoader.getResource(s3Url);
File downloadedS3Object = new File(resource.getFilename());
try (InputStream inputStream = resource.getInputStream()) {
Files.copy(inputStream, downloadedS3Object.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
}
public void uploadFileToS3(File file, String s3Url) throws IOException {
WritableResource resource = (WritableResource) resourceLoader.getResource(s3Url);
try (OutputStream outputStream = resource.getOutputStream()) {
Files.copy(file.toPath(), outputStream);
}
}
public void downloadMultipleS3Objects(String s3UrlPattern) throws IOException {
Resource[] allFileMatchingPatten = this.resourcePatternResolver.getResources(s3UrlPattern);
for (Resource resource : allFileMatchingPatten) {
String fileName = resource.getFilename();
fileName = fileName.substring(0, fileName.lastIndexOf("/") + 1);
File downloadedS3Object = new File(fileName);
try (InputStream inputStream = resource.getInputStream()) {
Files.copy(inputStream, downloadedS3Object.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
}
}
}
@@ -0,0 +1,64 @@
package com.baeldung.spring.cloud.aws.s3;
import java.io.File;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.ListObjectsV2Result;
import com.amazonaws.services.s3.model.S3ObjectSummary;
@Component
public class SpringCloudS3Service {
private static final Logger logger = LoggerFactory.getLogger(SpringCloudS3Service.class);
@Autowired
AmazonS3 amazonS3;
@Autowired
SpringCloudS3 springCloudS3;
public void createBucket(String bucketName) {
logger.debug("Creating S3 bucket: {}", bucketName);
amazonS3.createBucket(bucketName);
logger.info("{} bucket created successfully", bucketName);
}
public void downloadObject(String bucketName, String objectName) {
String s3Url = "s3://" + bucketName + "/" + objectName;
try {
springCloudS3.downloadS3Object(s3Url);
logger.info("{} file download result: {}", objectName, new File(objectName).exists());
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
public void uploadObject(String bucketName, String objectName) {
String s3Url = "s3://" + bucketName + "/" + objectName;
File file = new File(objectName);
try {
springCloudS3.uploadFileToS3(file, s3Url);
logger.info("{} file uploaded to S3", objectName);
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
public void deleteBucket(String bucketName) {
logger.trace("Deleting S3 objects under {} bucket...", bucketName);
ListObjectsV2Result listObjectsV2Result = amazonS3.listObjectsV2(bucketName);
for (S3ObjectSummary objectSummary : listObjectsV2Result.getObjectSummaries()) {
logger.info("Deleting S3 object: {}", objectSummary.getKey());
amazonS3.deleteObject(bucketName, objectSummary.getKey());
}
logger.info("Deleting S3 bucket: {}", bucketName);
amazonS3.deleteBucket(bucketName);
}
}
@@ -0,0 +1,36 @@
package com.baeldung.spring.cloud.aws.sns;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.aws.messaging.config.annotation.NotificationMessage;
import org.springframework.cloud.aws.messaging.config.annotation.NotificationSubject;
import org.springframework.cloud.aws.messaging.endpoint.NotificationStatus;
import org.springframework.cloud.aws.messaging.endpoint.annotation.NotificationMessageMapping;
import org.springframework.cloud.aws.messaging.endpoint.annotation.NotificationSubscriptionMapping;
import org.springframework.cloud.aws.messaging.endpoint.annotation.NotificationUnsubscribeConfirmationMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/topic-subscriber")
public class SNSEndpointController {
private static final Logger logger = LoggerFactory.getLogger(SNSEndpointController.class);
@NotificationMessageMapping
public void receiveNotification(@NotificationMessage String message, @NotificationSubject String subject) {
logger.info("Received message: {}, having subject: {}", message, subject);
}
@NotificationUnsubscribeConfirmationMapping
public void confirmSubscriptionMessage(NotificationStatus notificationStatus) {
logger.info("Unsubscribed from Topic");
notificationStatus.confirmSubscription();
}
@NotificationSubscriptionMapping
public void confirmUnsubscribeMessage(NotificationStatus notificationStatus) {
logger.info("Subscribed to Topic");
notificationStatus.confirmSubscription();
}
}
@@ -0,0 +1,16 @@
package com.baeldung.spring.cloud.aws.sns;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.aws.messaging.core.NotificationMessagingTemplate;
import org.springframework.stereotype.Component;
@Component
public class SNSMessageSender {
@Autowired
NotificationMessagingTemplate notificationMessagingTemplate;
public void send(String topicName, Object message, String subject) {
notificationMessagingTemplate.sendNotification(topicName, message, subject);
}
}
@@ -0,0 +1,46 @@
package com.baeldung.spring.cloud.aws.sqs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate;
import org.springframework.cloud.aws.messaging.listener.annotation.SqsListener;
import org.springframework.context.annotation.Lazy;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import java.util.concurrent.CountDownLatch;
@Component
@Lazy
public class SpringCloudSQS {
private static final Logger logger = LoggerFactory.getLogger(SpringCloudSQS.class);
static final String QUEUE_NAME = "spring-cloud-test-queue";
/*
* CountDownLatch is added to wait for messages
* during integration test
*/
CountDownLatch countDownLatch;
public void setCountDownLatch(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Autowired
QueueMessagingTemplate queueMessagingTemplate;
@SqsListener(QUEUE_NAME)
public void receiveMessage(String message, @Header("SenderId") String senderId) {
logger.info("Received message: {}, having SenderId: {}", message, senderId);
if (countDownLatch != null) {
countDownLatch.countDown();
}
}
public void send(String queueName, Object message) {
queueMessagingTemplate.convertAndSend(queueName, message);
}
}
@@ -0,0 +1,78 @@
AWSTemplateFormatVersion: 2010-09-09
Metadata:
'AWS::CloudFormation::Designer':
157e7d5f-5cb3-4a23-a50c-97e7f6c57173:
size:
width: 60
height: 60
position:
x: 450
'y': 90
z: 0
embeds: []
9bbaaa55-9cba-4555-a7c6-fb6ac248fd3a:
size:
width: 60
height: 60
position:
x: 260
'y': 90
z: 0
embeds: []
isassociatedwith:
- 157e7d5f-5cb3-4a23-a50c-97e7f6c57173
a7348729-a594-4dca-9b0a-e1c8d777dc3b:
size:
width: 60
height: 60
position:
x: 70
'y': 90
z: 0
embeds: []
Resources:
IAMRoleBaeldung:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/AmazonS3FullAccess'
Metadata:
'AWS::CloudFormation::Designer':
id: 157e7d5f-5cb3-4a23-a50c-97e7f6c57173
InstanceProfileBaeldung:
Type: 'AWS::IAM::InstanceProfile'
Properties:
Roles:
- !Ref IAMRoleBaeldung
Metadata:
'AWS::CloudFormation::Designer':
id: 9bbaaa55-9cba-4555-a7c6-fb6ac248fd3a
EC2Instance:
Type: 'AWS::EC2::Instance'
Properties:
ImageId: ami-2581aa40
InstanceType: t2.micro
IamInstanceProfile: !Ref InstanceProfileBaeldung
KeyName: Satish-Ohio
UserData: !Base64
'Fn::Join':
- ''
- - |
#!/bin/bash
- |
apt -y install openjdk-8-jre-headless
Metadata:
'AWS::CloudFormation::Designer':
id: a7348729-a594-4dca-9b0a-e1c8d777dc3b
DependsOn:
- InstanceProfileBaeldung
@@ -0,0 +1,14 @@
# Don't try to create DataSouce when running tests which don't need a DataSource
spring.autoconfigure.exclude=\
org.springframework.cloud.aws.autoconfigure.jdbc.AmazonRdsDatabaseAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
cloud.aws.region.auto=true
# Load instance profile credentials
cloud.aws.credentials.instanceProfile=true
# Disable auto cloud formation
cloud.aws.stack.auto=false
# Disable web environment
spring.main.web-environment=false
@@ -0,0 +1,14 @@
cloud.aws.credentials.accessKey=YourAccessKey
cloud.aws.credentials.secretKey=YourSecretKey
cloud.aws.region.static=us-east-1
cloud.aws.rds.spring-cloud-test-db
cloud.aws.rds.spring-cloud-test-db.password=se3retpass
# These 3 properties are optional
cloud.aws.rds.spring-cloud-test-db.username=testuser
cloud.aws.rds.spring-cloud-test-db.readReplicaSupport=true
cloud.aws.rds.spring-cloud-test-db.databaseName=test
# Disable auto cloudfromation
cloud.aws.stack.auto=false
@@ -0,0 +1,11 @@
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aws-context="http://www.springframework.org/schema/cloud/aws/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cloud/aws/context
http://www.springframework.org/schema/cloud/aws/context/spring-cloud-aws-context.xsd">
<aws-context:context-instance-data user-tags-map="instanceData" />
</beans>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
@@ -0,0 +1,73 @@
package com.baeldung.spring.cloud.aws;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.sns.AmazonSNS;
import com.amazonaws.services.sns.AmazonSNSClientBuilder;
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.junit.BeforeClass;
/**
* This class is needed only for testing. This is because we need to
* create AWS resources before Spring's Application context is created
* in a {@link BeforeClass} method. Since Autowired dependencies don't
* work in static context, we will use this class for AWS clients.
*/
public class SpringCloudAwsTestUtil {
private static String awsAccessKey;
private static String awsSecretKey;
private static String defaultRegion;
static {
try {
InputStream is = SpringCloudAwsTestUtil.class.getResourceAsStream("/application.properties");
Properties properties = new Properties();
properties.load(is);
awsAccessKey = properties.getProperty("cloud.aws.credentials.accessKey");
awsSecretKey = properties.getProperty("cloud.aws.credentials.secretKey");
defaultRegion = properties.getProperty("cloud.aws.region.static");
} catch (IOException e) {
e.printStackTrace();
}
}
public static AWSCredentials awsCredentials() {
return new BasicAWSCredentials(awsAccessKey, awsSecretKey);
}
public static AWSCredentialsProvider awsCredentialsProvider() {
return new AWSStaticCredentialsProvider(awsCredentials());
}
public static AmazonS3 amazonS3() {
return AmazonS3ClientBuilder.standard()
.withCredentials(awsCredentialsProvider())
.withRegion(defaultRegion)
.build();
}
public static AmazonSNS amazonSNS() {
return AmazonSNSClientBuilder.standard()
.withCredentials(awsCredentialsProvider())
.withRegion(defaultRegion)
.build();
}
public static AmazonSQS amazonSQS() {
return AmazonSQSClientBuilder.standard()
.withCredentials(awsCredentialsProvider())
.withRegion(defaultRegion)
.build();
}
}
@@ -0,0 +1,22 @@
package com.baeldung.spring.cloud.aws;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
*
* To run this Live Test, we need to have an AWS account and have API keys generated for programmatic access.
*
* Check the README file in this module for more information.
*
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringCloudAwsApplication.class)
public class SpringContextLiveTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}
@@ -0,0 +1,68 @@
package com.baeldung.spring.cloud.aws.ec2;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.ec2.AmazonEC2;
/**
*
* To run this Live Test, we need to have an AWS account and have API keys generated for programmatic access.
*
* Check the README file in this module for more information.
*
*/
@SpringBootTest
@RunWith(SpringRunner.class)
@TestPropertySource("classpath:application-test.properties")
public class EC2MetadataLiveTest {
private static final Logger logger = LoggerFactory.getLogger(EC2MetadataLiveTest.class);
private boolean serverEc2;
@Before
public void setUp() {
serverEc2 = Regions.getCurrentRegion() != null;
}
@Autowired
private EC2Metadata eC2Metadata;
@Autowired
private AmazonEC2 amazonEC2;
@Test
public void whenEC2ClinentNotNull_thenSuccess() {
assertThat(amazonEC2).isNotNull();
}
@Test
public void whenEC2MetadataNotNull_thenSuccess() {
assertThat(eC2Metadata).isNotNull();
}
@Test
public void whenMetdataValuesNotNull_thenSuccess() {
Assume.assumeTrue(serverEc2);
assertThat(eC2Metadata.getAmiId()).isNotEqualTo("N/A");
assertThat(eC2Metadata.getInstanceType()).isNotEqualTo("N/A");
}
@Test
public void whenMetadataLogged_thenSuccess() {
logger.info("Environment is EC2: {}", serverEc2);
logger.info(eC2Metadata.toString());
}
}
@@ -0,0 +1,53 @@
package com.baeldung.spring.cloud.aws.rds;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import static org.assertj.core.api.Assertions.assertThat;
/**
*
* To run this Live Test, we need to have an AWS account and have API keys generated for programmatic access.
*
* Check the README file in this module for more information.
*
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class SpringCloudRDSLiveTest {
@Autowired
DataSource dataSource;
@Test
public void whenDataSourceCreated_thenSuccess() {
assertThat(dataSource).isNotNull();
}
@Test
public void givenDataSource_whenConnectionCreated_thenSuccess() throws SQLException {
Connection connection = dataSource.getConnection();
assertThat(connection).isNotNull();
}
@Test
public void givenConnection_whenQueryExecuted_thenSuccess() throws SQLException {
Connection connection = dataSource.getConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT 1");
while (resultSet.next()) {
int result = resultSet.getInt(1);
assertThat(result).isEqualTo(1);
}
connection.close();
}
}
@@ -0,0 +1,108 @@
package com.baeldung.spring.cloud.aws.s3;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.ListObjectsV2Result;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import com.baeldung.spring.cloud.aws.SpringCloudAwsTestUtil;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
/**
*
* To run this Live Test, we need to have an AWS account and have API keys generated for programmatic access.
*
* Check the README file in this module for more information.
*
*/
@SpringBootTest
@RunWith(SpringRunner.class)
@TestPropertySource("classpath:application-test.properties")
public class SpringCloudS3LiveTest {
@Autowired
private SpringCloudS3 springCloudS3;
private static String bucketName;
private static String testFileToDownload;
private static String testFileToUpload;
private static String[] filesWithSimilarName;
private static List<File> similarNameFiles;
@BeforeClass
public static void setupResources() throws IOException {
bucketName = UUID.randomUUID().toString();
testFileToDownload = "test-file-download.txt";
testFileToUpload = "test-file-upload.txt";
filesWithSimilarName = new String[] { "foo/hello-apple.txt", "foo/hello-orange.txt", "bar/hello-grapes.txt", };
similarNameFiles = new ArrayList<>();
for (String name : filesWithSimilarName) {
similarNameFiles.add(new File(name.substring(0, name.lastIndexOf("/") + 1)));
}
Files.write(Paths.get(testFileToUpload), "Hello World Uploaded!".getBytes());
AmazonS3 amazonS3 = SpringCloudAwsTestUtil.amazonS3();
amazonS3.createBucket(bucketName);
amazonS3.putObject(bucketName, testFileToDownload, "Hello World");
for (String s3Key : filesWithSimilarName) {
amazonS3.putObject(bucketName, s3Key, "Hello World");
}
}
@Test
public void whenS3ObjectDownloaded_thenSuccess() throws IOException {
String s3Url = "s3://" + bucketName + "/" + testFileToDownload;
springCloudS3.downloadS3Object(s3Url);
assertThat(new File(testFileToDownload)).exists();
}
@Test
public void whenS3ObjectUploaded_thenSuccess() throws IOException {
String s3Url = "s3://" + bucketName + "/" + testFileToUpload;
File file = new File(testFileToUpload);
springCloudS3.uploadFileToS3(file, s3Url);
}
@Test
public void whenMultipleS3ObjectsDownloaded_thenSuccess() throws IOException {
String s3Url = "s3://" + bucketName + "/**/hello-*.txt";
springCloudS3.downloadMultipleS3Objects(s3Url);
similarNameFiles.forEach(f -> assertThat(f).exists());
}
@AfterClass
public static void cleanUpResources() {
AmazonS3 amazonS3 = SpringCloudAwsTestUtil.amazonS3();
ListObjectsV2Result listObjectsV2Result = amazonS3.listObjectsV2(bucketName);
for (S3ObjectSummary objectSummary : listObjectsV2Result.getObjectSummaries()) {
amazonS3.deleteObject(bucketName, objectSummary.getKey());
}
amazonS3.deleteBucket(bucketName);
new File(testFileToDownload).delete();
new File(testFileToUpload).delete();
similarNameFiles.forEach(File::delete);
}
}
@@ -0,0 +1,38 @@
package com.baeldung.spring.cloud.aws.sns;
import org.junit.Before;
import org.junit.Test;
import org.springframework.cloud.aws.messaging.endpoint.NotificationStatus;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
public class SNSEndpointControllerUnitTest {
SNSEndpointController snsEndpointController;
@Before
public void setUp() {
snsEndpointController = new SNSEndpointController();
}
@Test
public void whenReceivedNotificationInvoked_thenSuccess() {
snsEndpointController.receiveNotification("Message", "Subject");
}
@Test
public void whenConfirmUnsubscribeReturned_thenSuccess() {
NotificationStatus notificationStatus = mock(NotificationStatus.class);
doNothing().when(notificationStatus).confirmSubscription();
snsEndpointController.confirmUnsubscribeMessage(notificationStatus);
}
@Test
public void whenConfirmSubscriptionReturned_thenSuccess() {
NotificationStatus notificationStatus = mock(NotificationStatus.class);
doNothing().when(notificationStatus).confirmSubscription();
snsEndpointController.confirmSubscriptionMessage(notificationStatus);
}
}
@@ -0,0 +1,68 @@
package com.baeldung.spring.cloud.aws.sns;
import java.util.UUID;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import com.amazonaws.services.sns.AmazonSNS;
import com.amazonaws.services.sns.model.CreateTopicResult;
import com.baeldung.spring.cloud.aws.SpringCloudAwsTestUtil;
import com.baeldung.spring.cloud.aws.sqs.Greeting;
/**
*
* To run this Live Test, we need to have an AWS account and have API keys generated for programmatic access.
*
* Check the README file in this module for more information.
*
*/
@SpringBootTest
@RunWith(SpringRunner.class)
@TestPropertySource("classpath:application-test.properties")
public class SpringCloudSNSLiveTest {
@Autowired
private SNSMessageSender snsMessageSender;
private static String topicName;
private static String topicArn;
@BeforeClass
public static void setupAwsResources() {
topicName = UUID.randomUUID().toString();
AmazonSNS amazonSNS = SpringCloudAwsTestUtil.amazonSNS();
CreateTopicResult result = amazonSNS.createTopic(topicName);
topicArn = result.getTopicArn();
}
@Test
public void whenMessagePublished_thenSuccess() {
String subject = "Test Message";
String message = "Hello World";
snsMessageSender.send(topicName, message, subject);
}
@Test
public void whenConvertedMessagePublished_thenSuccess() {
String subject = "Test Message";
Greeting message = new Greeting("Helo", "World");
snsMessageSender.send(topicName, message, subject);
}
@AfterClass
public static void cleanupAwsResources() {
AmazonSNS amazonSNS = SpringCloudAwsTestUtil.amazonSNS();
amazonSNS.deleteTopic(topicArn);
}
}
@@ -0,0 +1,63 @@
package com.baeldung.spring.cloud.aws.sqs;
public class Greeting {
private String message;
private String name;
public Greeting() {
}
public Greeting(String mesage, String name) {
this.message = mesage;
this.name = name;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((message == null) ? 0 : message.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Greeting other = (Greeting) obj;
if (message == null) {
if (other.message != null)
return false;
} else if (!message.equals(other.message))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
@@ -0,0 +1,142 @@
package com.baeldung.spring.cloud.aws.sqs;
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.model.CreateQueueResult;
import com.amazonaws.services.sqs.model.PurgeQueueRequest;
import com.amazonaws.services.sqs.model.ReceiveMessageRequest;
import com.amazonaws.services.sqs.model.ReceiveMessageResult;
import com.baeldung.spring.cloud.aws.SpringCloudAwsTestUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Lazy;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import static org.assertj.core.api.Assertions.assertThat;
/**
*
* To run this Live Test, we need to have an AWS account and have API keys generated for programmatic access.
*
* Check the README file in this module for more information.
*
*/
@SpringBootTest
@RunWith(SpringRunner.class)
@TestPropertySource("classpath:application-test.properties")
public class SpringCloudSQSLiveTest {
private static final Logger logger = LoggerFactory.getLogger(SpringCloudSQSLiveTest.class);
@Autowired
@Lazy
private SpringCloudSQS springCloudSQS;
private static String receiveQueueName;
private static String receiveQueueUrl;
private static String sendQueueName;
private static String sendQueueURl;
@BeforeClass
public static void setupAwsResources() {
sendQueueName = UUID.randomUUID().toString();
receiveQueueName = SpringCloudSQS.QUEUE_NAME;
AmazonSQS amazonSQS = SpringCloudAwsTestUtil.amazonSQS();
CreateQueueResult receiveQueue = amazonSQS.createQueue(receiveQueueName);
receiveQueueUrl = receiveQueue.getQueueUrl();
CreateQueueResult sendQueue = amazonSQS.createQueue(sendQueueName);
sendQueueURl = sendQueue.getQueueUrl();
}
@Test
public void whenMessageSentAndVerified_thenSuccess() throws InterruptedException {
String message = "Hello World";
springCloudSQS.send(sendQueueName, message);
AmazonSQS amazonSQS = SpringCloudAwsTestUtil.amazonSQS();
ReceiveMessageRequest request = new ReceiveMessageRequest(sendQueueURl);
request.setMaxNumberOfMessages(1);
ReceiveMessageResult result = null;
do {
result = amazonSQS.receiveMessage(request);
if (result.getMessages().size() == 0) {
logger.info("Message not received at first time, waiting for 1 second");
}
} while (result.getMessages().size() == 0);
assertThat(result.getMessages().get(0).getBody()).isEqualTo(message);
// Delete message so that it doen't interfere with other test
amazonSQS.deleteMessage(sendQueueURl, result.getMessages().get(0).getReceiptHandle());
}
@Test
public void whenConvertedMessageSentAndVerified_thenSuccess() throws InterruptedException, IOException {
Greeting message = new Greeting("Hello", "World");
springCloudSQS.send(sendQueueName, message);
AmazonSQS amazonSQS = SpringCloudAwsTestUtil.amazonSQS();
ReceiveMessageRequest request = new ReceiveMessageRequest(sendQueueURl);
request.setMaxNumberOfMessages(1);
ReceiveMessageResult result = null;
do {
result = amazonSQS.receiveMessage(request);
if (result.getMessages().size() == 0) {
logger.info("Message not received at first time, waiting for 1 second");
}
} while (result.getMessages().size() == 0);
assertThat(new ObjectMapper().readValue(result.getMessages().get(0).getBody(), Greeting.class)).isEqualTo(message);
// Delete message so that it doen't interfere with other test
amazonSQS.deleteMessage(sendQueueURl, result.getMessages().get(0).getReceiptHandle());
}
@Test
public void givenMessageSent_whenMessageReceived_thenSuccess() throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(5);
springCloudSQS.setCountDownLatch(countDownLatch);
AmazonSQS amazonSQS = SpringCloudAwsTestUtil.amazonSQS();
for (int i = 0; i < 5; i++) {
amazonSQS.sendMessage(receiveQueueUrl, "Hello World " + i);
logger.info("Sent message {}, waiting for 1 second", i + 1);
Thread.sleep(1000L);
}
countDownLatch.await();
}
@AfterClass
public static void cleanupAwsResources() {
AmazonSQS amazonSQS = SpringCloudAwsTestUtil.amazonSQS();
PurgeQueueRequest receiveQueuePurge = new PurgeQueueRequest(receiveQueueUrl);
amazonSQS.purgeQueue(receiveQueuePurge);
amazonSQS.deleteQueue(receiveQueueUrl);
PurgeQueueRequest sendQueuePurge = new PurgeQueueRequest(sendQueueURl);
amazonSQS.purgeQueue(sendQueuePurge);
amazonSQS.deleteQueue(sendQueueURl);
}
}
@@ -0,0 +1,4 @@
# Don't try to create DataSouce when running tests which don't need a DataSource
spring.autoconfigure.exclude=\
org.springframework.cloud.aws.autoconfigure.jdbc.AmazonRdsDatabaseAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
@@ -0,0 +1,21 @@
## Spring Cloud Bootstrap
This module contains articles about bootstrapping Spring Cloud applications
### Relevant Articles:
- [Spring Cloud Bootstrapping](http://www.baeldung.com/spring-cloud-bootstrapping)
- [Spring Cloud Securing Services](http://www.baeldung.com/spring-cloud-securing-services)
- [Spring Cloud Tracing Services with Zipkin](http://www.baeldung.com/tracing-services-with-zipkin)
- [Spring Cloud Series The Gateway Pattern](http://www.baeldung.com/spring-cloud-gateway-pattern)
- [Spring Cloud Adding Angular 4](http://www.baeldung.com/spring-cloud-angular)
### Running the Project
- To run the project:
- copy the appliction-config folder to c:\Users\{username}\ on Windows or /home/{username}/ on *nix. Then open a git bash terminal in application-config and run:
- git init
- git add .
- git commit -m "First commit"
- start the config server
- start the discovery server
- start all the other servers in any order (gateway, svc-book, svc-rating, zipkin)
@@ -0,0 +1,20 @@
spring.application.name=book-service
server.port=8083
resource.returnString=hello cloud
resource.user.returnString=hello cloud user
resource.admin.returnString=hello cloud admin
eureka.client.region = default
eureka.client.registryFetchIntervalSeconds = 5
management.security.sessions=never
logging.level.org.springframework.web.=debug
logging.level.org.springframework.security=debug
spring.redis.host=localhost
spring.redis.port=6379
spring.sleuth.sampler.percentage=1.0
spring.sleuth.web.skipPattern=(^cleanup.*)
@@ -0,0 +1,11 @@
spring.application.name=discovery
server.port=8082
eureka.instance.hostname=localhost
eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
spring.redis.host=localhost
spring.redis.port=6379
@@ -0,0 +1,30 @@
spring.application.name=gateway
server.port=8080
eureka.client.region = default
eureka.client.registryFetchIntervalSeconds = 5
management.security.sessions=always
zuul.routes.book-service.path=/book-service/**
zuul.routes.book-service.sensitive-headers=Set-Cookie,Authorization
hystrix.command.book-service.execution.isolation.thread.timeoutInMilliseconds=600000
zuul.routes.rating-service.path=/rating-service/**
zuul.routes.rating-service.sensitive-headers=Set-Cookie,Authorization
hystrix.command.rating-service.execution.isolation.thread.timeoutInMilliseconds=600000
zuul.routes.discovery.path=/discovery/**
zuul.routes.discovery.sensitive-headers=Set-Cookie,Authorization
zuul.routes.discovery.url=http://localhost:8082
hystrix.command.discovery.execution.isolation.thread.timeoutInMilliseconds=600000
logging.level.org.springframework.web.=debug
logging.level.org.springframework.security=debug
logging.level.org.springframework.cloud.netflix.zuul=debug
spring.redis.host=localhost
spring.redis.port=6379
spring.sleuth.sampler.percentage=1.0
spring.sleuth.web.skipPattern=(^cleanup.*|.+favicon.*)
@@ -0,0 +1,20 @@
spring.application.name=rating-service
server.port=8084
resource.returnString=hello cloud
resource.user.returnString=hello cloud user
resource.admin.returnString=hello cloud admin
eureka.client.region = default
eureka.client.registryFetchIntervalSeconds = 5
management.security.sessions=never
logging.level.org.springframework.web.=debug
logging.level.org.springframework.security=debug
spring.redis.host=localhost
spring.redis.port=6379
spring.sleuth.sampler.percentage=1.0
spring.sleuth.web.skipPattern=(^cleanup.*)
@@ -0,0 +1,7 @@
spring.application.name=zipkin
server.port=9411
eureka.client.region = default
eureka.client.registryFetchIntervalSeconds = 5
logging.level.org.springframework.web=debug
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>config</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>config</name>
<parent>
<artifactId>parent-boot-1</artifactId>
<groupId>com.baeldung</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../../parent-boot-1</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<properties>
<spring-cloud-dependencies.version>Brixton.SR7</spring-cloud-dependencies.version>
</properties>
</project>
@@ -0,0 +1,15 @@
package com.baeldung.spring.cloud.bootstrap.config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableConfigServer
@EnableEurekaClient
public class ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class, args);
}
}
@@ -0,0 +1,23 @@
package com.baeldung.spring.cloud.bootstrap.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("configUser").password("configPassword").roles("SYSTEM");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().hasRole("SYSTEM").and().httpBasic().and().csrf().disable();
}
}

Some files were not shown because too many files have changed in this diff Show More