2222import java .util .Collections ;
2323import java .util .List ;
2424import java .util .Properties ;
25- import java .util .function .Consumer ;
25+ import java .util .concurrent .CompletableFuture ;
26+ import java .util .concurrent .Executor ;
27+ import java .util .stream .Collectors ;
2628
2729import org .apache .commons .logging .Log ;
2830import org .apache .commons .logging .LogFactory ;
4547
4648/**
4749 * @author Clay McCoy
50+ * @author Noah Hanka
4851 * @author Scott Frederick
4952 * @author Daniel Aiken
5053 */
@@ -64,18 +67,26 @@ public class AwsS3EnvironmentRepository implements EnvironmentRepository, Ordere
6467
6568 private final boolean useApplicationAsDirectory ;
6669
70+ private final Executor executor ;
71+
6772 protected int order = Ordered .LOWEST_PRECEDENCE ;
6873
6974 public AwsS3EnvironmentRepository (S3Client s3Client , String bucketName , ConfigServerProperties server ) {
70- this (s3Client , bucketName , false , server );
75+ this (s3Client , bucketName , false , server , null );
7176 }
7277
7378 public AwsS3EnvironmentRepository (S3Client s3Client , String bucketName , boolean useApplicationAsDirectory ,
7479 ConfigServerProperties server ) {
80+ this (s3Client , bucketName , useApplicationAsDirectory , server , null );
81+ }
82+
83+ public AwsS3EnvironmentRepository (S3Client s3Client , String bucketName , boolean useApplicationAsDirectory ,
84+ ConfigServerProperties server , Executor executor ) {
7585 this .s3Client = s3Client ;
7686 this .bucketName = bucketName ;
7787 this .serverProperties = server ;
7888 this .useApplicationAsDirectory = useApplicationAsDirectory ;
89+ this .executor = (executor != null ) ? executor : Runnable ::run ;
7990 }
8091
8192 @ Override
@@ -126,77 +137,70 @@ public Environment findOne(String specifiedApplication, String specifiedProfiles
126137
127138 private void addPropertySources (Environment environment , List <String > apps , String [] profiles ,
128139 List <String > labels ) {
140+ List <S3ConfigFile > allConfigs = new ArrayList <>();
129141 for (String label : labels ) {
130142 // If we have profiles, add property sources with those profiles
131143 for (String profile : profiles ) {
132- addPropertySourcesForApps (apps ,
133- app -> addProfileSpecificPropertySource (environment , app , profile , label ));
144+ apps .forEach (app -> allConfigs .addAll (getProfileSpecificS3ConfigFiles (app , profile , label )));
134145 }
135146 }
136147
137148 // If we have no profiles just add property sources for all apps
138149 if (profiles .length == 0 ) {
139150 for (String label : labels ) {
140- addPropertySourcesForApps (apps ,
141- app -> addNonProfileSpecificPropertySource (environment , app , null , label ));
151+ apps .forEach (app -> allConfigs .addAll (getNonProfileSpecificS3ConfigFiles (app , null , label )));
142152 }
143153 }
144154 else {
145155 for (String label : labels ) {
146156 // If we have profiles, we still need to add property sources from files
147- // that
148- // are not profile specific but we pass
149- // along the profiles as well so we can check if any non-profile specific
150- // YAML
151- // files have profile specific documents
152- // within them
157+ // that are not profile specific but we pass along the profiles as well
158+ // so we can check if any non-profile specific YAML files have profile
159+ // specific documents within them
153160 for (String profile : profiles ) {
154- addPropertySourcesForApps (apps ,
155- app -> addNonProfileSpecificPropertySource (environment , app , profile , label ));
161+ apps .forEach (app -> allConfigs .addAll (getNonProfileSpecificS3ConfigFiles (app , profile , label )));
156162 }
157163 }
158164 }
159- }
160165
161- private void addPropertySourcesForApps (List <String > apps , Consumer <String > addPropertySource ) {
162- apps .forEach (addPropertySource );
166+ List <CompletableFuture <Void >> futures = allConfigs .stream ()
167+ .map (config -> CompletableFuture .runAsync (config ::read , executor ))
168+ .collect (Collectors .toList ());
169+ CompletableFuture .allOf (futures .toArray (new CompletableFuture [0 ])).join ();
170+
171+ for (S3ConfigFile s3ConfigFile : allConfigs ) {
172+ addPropertySource (environment , s3ConfigFile );
173+ }
163174 }
164175
165- private void addProfileSpecificPropertySource ( Environment environment , String app , String profile , String label ) {
166- List < S3ConfigFile > s3ConfigFiles = getS3ConfigFile (app , profile , label , this ::getS3PropertiesOrJsonConfigFile ,
176+ private List < S3ConfigFile > getProfileSpecificS3ConfigFiles ( String app , String profile , String label ) {
177+ return getS3ConfigFile (app , profile , label , this ::getS3PropertiesOrJsonConfigFile ,
167178 this ::getProfileSpecificS3ConfigFileYaml );
168- addPropertySource (environment , s3ConfigFiles );
169179 }
170180
171- private void addNonProfileSpecificPropertySource (Environment environment , String app , String profile ,
172- String label ) {
173- List <S3ConfigFile > s3ConfigFiles = getS3ConfigFile (app , profile , label ,
174- this ::getNonProfileSpecificPropertiesOrJsonConfigFile , this ::getNonProfileSpecificS3ConfigFileYaml );
175- addPropertySource (environment , s3ConfigFiles );
176- }
177-
178- private void addPropertySource (Environment environment , List <S3ConfigFile > s3ConfigFiles ) {
179- for (S3ConfigFile s3ConfigFile : s3ConfigFiles ) {
180- final Properties config = s3ConfigFile .read ();
181- // This logic handles the case where the s3 file is a YAML file that is
182- // not profile specific (ie it does not have -<profile> in the name)
183- // and does not have any profile specific documents in it. In this case we do
184- // not want to include this
185- // property source we only want to include the document for the default
186- // profile. When we create
187- // the S3ConfigFile for this file we set the
188- // shouldIncludeWithEmptyProperties to false
189- // in ProfileSpecificYamlDocumentS3ConfigFile for this specific case.
190- if (config != null ) {
191- if (!config .isEmpty () || s3ConfigFile .isShouldIncludeWithEmptyProperties ()) {
192- environment .setVersion (s3ConfigFile .getVersion ());
193- config .putAll (serverProperties .getOverrides ());
194- PropertySource propertySource = new PropertySource (s3ConfigFile .getName (), config );
195- if (LOG .isDebugEnabled ()) {
196- LOG .debug ("Adding property source to environment " + propertySource );
197- }
198- environment .add (propertySource );
181+ private List <S3ConfigFile > getNonProfileSpecificS3ConfigFiles (String app , String profile , String label ) {
182+ return getS3ConfigFile (app , profile , label , this ::getNonProfileSpecificPropertiesOrJsonConfigFile ,
183+ this ::getNonProfileSpecificS3ConfigFileYaml );
184+ }
185+
186+ private void addPropertySource (Environment environment , S3ConfigFile s3ConfigFile ) {
187+ final Properties config = s3ConfigFile .read ();
188+ // This logic handles the case where the s3 file is a YAML file that is
189+ // not profile specific (ie it does not have -<profile> in the name)
190+ // and does not have any profile specific documents in it. In this case we do
191+ // not want to include this property source we only want to include the
192+ // document for the default profile. When we create the S3ConfigFile for
193+ // this file we set the shouldIncludeWithEmptyProperties to false
194+ // in ProfileSpecificYamlDocumentS3ConfigFile for this specific case.
195+ if (config != null ) {
196+ if (!config .isEmpty () || s3ConfigFile .isShouldIncludeWithEmptyProperties ()) {
197+ environment .setVersion (s3ConfigFile .getVersion ());
198+ config .putAll (serverProperties .getOverrides ());
199+ PropertySource propertySource = new PropertySource (s3ConfigFile .getName (), config );
200+ if (LOG .isDebugEnabled ()) {
201+ LOG .debug ("Adding property source to environment " + propertySource );
199202 }
203+ environment .add (propertySource );
200204 }
201205 }
202206 }
@@ -348,8 +352,8 @@ protected S3ConfigFile(String application, String profile, String label, String
348352 this .profile = profile ;
349353 this .label = label ;
350354 this .bucketName = bucketName ;
351- this .s3Client = s3Client ;
352355 this .useApplicationAsDirectory = useApplicationAsDirectory ;
356+ this .s3Client = s3Client ;
353357 }
354358
355359 String getVersion () {
@@ -437,11 +441,10 @@ class PropertyS3ConfigFile extends S3ConfigFile {
437441 PropertyS3ConfigFile (String application , String profile , String label , String bucketName ,
438442 boolean useApplicationAsDirectory , S3Client s3Client ) {
439443 super (application , profile , label , bucketName , useApplicationAsDirectory , s3Client );
440- this .properties = read ();
441444 }
442445
443446 @ Override
444- public Properties read () {
447+ public synchronized Properties read () {
445448 if (this .properties != null ) {
446449 return this .properties ;
447450 }
@@ -453,6 +456,7 @@ public Properties read() {
453456 LOG .warn ("Exception thrown when reading property file" , e );
454457 throw new IllegalStateException ("Cannot load environment" , e );
455458 }
459+ this .properties = props ;
456460 return props ;
457461 }
458462
@@ -478,8 +482,6 @@ class YamlS3ConfigFile extends S3ConfigFile {
478482 final YamlProcessor .DocumentMatcher ... documentMatchers ) {
479483 super (application , profile , label , bucketName , useApplicationAsDirectory , s3Client );
480484 this .documentMatchers = documentMatchers ;
481- this .properties = read ();
482-
483485 }
484486
485487 protected static boolean profileMatchesActivateProperty (String profile , Properties properties ) {
@@ -493,15 +495,16 @@ protected static boolean onProfilePropertyExists(Properties properties) {
493495 }
494496
495497 @ Override
496- public Properties read () {
498+ public synchronized Properties read () {
497499 if (properties != null ) {
498500 return properties ;
499501 }
500502 final YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean ();
501503 try (InputStream in = getObject ()) {
502504 yaml .setResources (new InputStreamResource (in ));
503505 yaml .setDocumentMatchers (documentMatchers );
504- return yaml .getObject ();
506+ this .properties = yaml .getObject ();
507+ return this .properties ;
505508 }
506509 catch (Exception e ) {
507510 LOG .warn ("Could not read YAML file" , e );
@@ -567,7 +570,6 @@ class JsonS3ConfigFile extends YamlS3ConfigFile {
567570 JsonS3ConfigFile (String application , String profile , String label , String bucketName ,
568571 boolean useApplicationAsDirectory , S3Client s3Client ) {
569572 super (application , profile , label , bucketName , useApplicationAsDirectory , s3Client );
570- this .properties = read ();
571573 }
572574
573575 @ Override
0 commit comments