16
16
package software .amazon .awssdk .profiles ;
17
17
18
18
import java .nio .file .Path ;
19
+ import java .util .Arrays ;
19
20
import java .util .Objects ;
21
+ import java .util .Optional ;
22
+ import java .util .concurrent .atomic .AtomicReference ;
20
23
import java .util .function .Supplier ;
21
24
import software .amazon .awssdk .annotations .SdkPublicApi ;
22
25
import software .amazon .awssdk .profiles .internal .ProfileFileRefresher ;
@@ -36,21 +39,53 @@ public interface ProfileFileSupplier extends Supplier<ProfileFile>, SdkAutoClose
36
39
default void close () {
37
40
}
38
41
42
+ /**
43
+ * Creates a {@link ProfileFileSupplier} capable of producing multiple profile objects by aggregating the default
44
+ * credentials and configuration files as determined by {@link ProfileFileLocation#credentialsFileLocation()} abd
45
+ * {@link ProfileFileLocation#configurationFileLocation()}. This supplier will return a new ProfileFile instance only once
46
+ * either disk file has been modified. Multiple calls to the supplier while both disk files are unchanged will return the
47
+ * same object.
48
+ *
49
+ * @return Implementation of {@link ProfileFileSupplier} that is capable of supplying a new aggregate profile when either file
50
+ * has been modified.
51
+ */
52
+ static ProfileFileSupplier defaultSupplier () {
53
+ Optional <ProfileFileSupplier > credentialsSupplierOptional
54
+ = ProfileFileLocation .credentialsFileLocation ()
55
+ .map (path -> reloadWhenModified (path , ProfileFile .Type .CREDENTIALS ));
56
+
57
+ Optional <ProfileFileSupplier > configurationSupplierOptional
58
+ = ProfileFileLocation .configurationFileLocation ()
59
+ .map (path -> reloadWhenModified (path , ProfileFile .Type .CONFIGURATION ));
60
+
61
+ ProfileFileSupplier supplier = () -> null ;
62
+ if (credentialsSupplierOptional .isPresent () && configurationSupplierOptional .isPresent ()) {
63
+ supplier = aggregate (credentialsSupplierOptional .get (), configurationSupplierOptional .get ());
64
+ } else if (credentialsSupplierOptional .isPresent ()) {
65
+ supplier = credentialsSupplierOptional .get ();
66
+ } else if (configurationSupplierOptional .isPresent ()) {
67
+ supplier = configurationSupplierOptional .get ();
68
+ }
69
+
70
+ return supplier ;
71
+ }
72
+
39
73
/**
40
74
* Creates a {@link ProfileFileSupplier} capable of producing multiple profile objects from a file. This supplier will
41
75
* return a new ProfileFile instance only once the disk file has been modified. Multiple calls to the supplier while the
42
76
* disk file is unchanged will return the same object.
43
77
*
44
78
* @param path Path to the file to read from.
79
+ * @param type The type of file. See {@link ProfileFile.Type} for possible values.
45
80
* @return Implementation of {@link ProfileFileSupplier} that is capable of supplying a new profile when the file
46
81
* has been modified.
47
82
*/
48
- static ProfileFileSupplier reloadWhenModified (Path path ) {
83
+ static ProfileFileSupplier reloadWhenModified (Path path , ProfileFile . Type type ) {
49
84
return new ProfileFileSupplier () {
50
85
51
86
final ProfileFile .Builder builder = ProfileFile .builder ()
52
87
.content (path )
53
- .type (ProfileFile . Type . CREDENTIALS );
88
+ .type (type );
54
89
55
90
final ProfileFileRefresher refresher = ProfileFileRefresher .builder ()
56
91
.profileFile (builder ::build )
@@ -69,21 +104,6 @@ public void close() {
69
104
};
70
105
}
71
106
72
- /**
73
- * Creates a {@link ProfileFileSupplier} capable of producing a single profile object from a file.
74
- *
75
- * @param path Path to the file to read from.
76
- * @return Implementation of {@link ProfileFileSupplier} that is capable of supplying a single profile.
77
- */
78
- static ProfileFileSupplier fixedProfileFile (Path path ) {
79
- ProfileFile profileFile = ProfileFile .builder ()
80
- .content (path )
81
- .type (ProfileFile .Type .CREDENTIALS )
82
- .build ();
83
-
84
- return () -> profileFile ;
85
- }
86
-
87
107
/**
88
108
* Creates a {@link ProfileFileSupplier} that produces an existing profile.
89
109
*
@@ -95,14 +115,46 @@ static ProfileFileSupplier fixedProfileFile(ProfileFile profileFile) {
95
115
}
96
116
97
117
/**
98
- * creates a {@link ProfileFileSupplier} that produces an existing non-null profile. If the given profile
99
- * is null, then the created supplier will also be null .
118
+ * Creates a {@link ProfileFileSupplier} by combining the {@link ProfileFile} objects from two {@code ProfileFileSupplier}s.
119
+ * Objects are passed into {@link ProfileFile.Aggregator} .
100
120
*
101
- * @param profileFile Profile object to supply.
102
- * @return Implementation of {@link ProfileFileSupplier} that is capable of supplying a single profile.
121
+ * @param suppliers Array of {@code ProfileFileSupplier} objects. {@code ProfileFile} objects are passed to
122
+ * {@link ProfileFile.Aggregator#addFile(ProfileFile)} in the same argument order as the supplier that
123
+ * generated it.
124
+ * @return Implementation of {@link ProfileFileSupplier} aggregating results from the supplier objects.
103
125
*/
104
- static ProfileFileSupplier wrapIntoNullableSupplier (ProfileFile profileFile ) {
105
- return Objects .nonNull (profileFile ) ? () -> profileFile : null ;
126
+ static ProfileFileSupplier aggregate (ProfileFileSupplier ... suppliers ) {
127
+
128
+ return new ProfileFileSupplier () {
129
+
130
+ final AtomicReference <ProfileFile > currentAggregateProfileFile = new AtomicReference <>();
131
+
132
+ @ Override
133
+ public ProfileFile get () {
134
+ ProfileFile .Aggregator aggregator = ProfileFile .aggregator ();
135
+ for (ProfileFileSupplier supplier : suppliers ) {
136
+ aggregator .addFile (supplier .get ());
137
+ }
138
+
139
+ return refreshAndGetCurrentAggregate (aggregator );
140
+ }
141
+
142
+ @ Override
143
+ public void close () {
144
+ Arrays .stream (suppliers ).forEach (ProfileFileSupplier ::close );
145
+ }
146
+
147
+ private ProfileFile refreshAndGetCurrentAggregate (ProfileFile .Aggregator aggregator ) {
148
+ ProfileFile current = currentAggregateProfileFile .get ();
149
+ ProfileFile next = aggregator .build ();
150
+ if (!Objects .equals (current , next )) {
151
+ currentAggregateProfileFile .compareAndSet (current , next );
152
+ }
153
+
154
+ return currentAggregateProfileFile .get ();
155
+ }
156
+
157
+ };
106
158
}
107
159
108
160
}
0 commit comments