15
15
16
16
package software .amazon .smithy .aws .typescript .codegen ;
17
17
18
+ import static software .amazon .smithy .typescript .codegen .integration .RuntimeClientPlugin .Convention .HAS_CONFIG ;
19
+ import static software .amazon .smithy .typescript .codegen .integration .RuntimeClientPlugin .Convention .HAS_MIDDLEWARE ;
20
+
18
21
import java .util .Collections ;
22
+ import java .util .List ;
19
23
import java .util .Map ;
24
+ import java .util .Set ;
20
25
import java .util .function .Consumer ;
21
26
22
27
import software .amazon .smithy .aws .traits .ServiceTrait ;
23
28
import software .amazon .smithy .codegen .core .SymbolProvider ;
24
29
import software .amazon .smithy .model .Model ;
25
- import software .amazon .smithy .model .shapes .ServiceShape ;
30
+ import software .amazon .smithy .model .knowledge .OperationIndex ;
31
+ import software .amazon .smithy .model .shapes .OperationShape ;
32
+ import software .amazon .smithy .model .shapes .Shape ;
26
33
import software .amazon .smithy .typescript .codegen .LanguageTarget ;
27
34
import software .amazon .smithy .typescript .codegen .TypeScriptDependency ;
28
35
import software .amazon .smithy .typescript .codegen .TypeScriptSettings ;
29
36
import software .amazon .smithy .typescript .codegen .TypeScriptWriter ;
37
+ import software .amazon .smithy .typescript .codegen .integration .RuntimeClientPlugin ;
30
38
import software .amazon .smithy .typescript .codegen .integration .TypeScriptIntegration ;
39
+ import software .amazon .smithy .utils .ListUtils ;
31
40
import software .amazon .smithy .utils .MapUtils ;
41
+ import software .amazon .smithy .utils .SetUtils ;
32
42
33
43
/**
34
44
* AWS S3 client configuration.
35
45
*/
36
46
public final class AddS3Config implements TypeScriptIntegration {
37
47
48
+ private static final Set <String > S3_MD5_OPERATIONS = SetUtils .of (
49
+ "DeleteObjects" ,
50
+ "PutBucketCors" ,
51
+ "PutBucketLifecycle" ,
52
+ "PutBucketLifecycleConfiguration" ,
53
+ "PutBucketPolicy" ,
54
+ "PutBucketTagging" ,
55
+ "PutBucketReplication"
56
+ );
57
+
58
+ private static final Set <String > SSEC_OPERATIONS = SetUtils .of ("SSECustomerKey" , "CopySourceSSECustomerKey" );
59
+
60
+ private static final Set <String > NON_BUCKET_ENDPOINT_OPERATIONS = SetUtils .of (
61
+ "CreateBucket" ,
62
+ "DeleteBucket" ,
63
+ "ListBuckets"
64
+ );
65
+
38
66
@ Override
39
67
public void addConfigInterfaceFields (TypeScriptSettings settings , Model model , SymbolProvider symbolProvider ,
40
68
TypeScriptWriter writer ) {
41
- if (!needsS3Config (settings .getService (model ))) {
69
+ if (!testServiceId (settings .getService (model ))) {
42
70
return ;
43
71
}
44
72
writer .writeDocs ("Whether to escape request path when signing the request." )
@@ -53,7 +81,7 @@ public void addConfigInterfaceFields(TypeScriptSettings settings, Model model, S
53
81
@ Override
54
82
public Map <String , Consumer <TypeScriptWriter >> getRuntimeConfigWriters (TypeScriptSettings settings , Model model ,
55
83
SymbolProvider symbolProvider , LanguageTarget target ) {
56
- if (!needsS3Config (settings .getService (model ))) {
84
+ if (!testServiceId (settings .getService (model ))) {
57
85
return Collections .emptyMap ();
58
86
}
59
87
switch (target ) {
@@ -77,8 +105,71 @@ public Map<String, Consumer<TypeScriptWriter>> getRuntimeConfigWriters(TypeScrip
77
105
}
78
106
}
79
107
80
- private static boolean needsS3Config (ServiceShape service ) {
81
- String serviceId = service .getTrait (ServiceTrait .class ).map (ServiceTrait ::getSdkId ).orElse ("" );
82
- return serviceId .equals ("S3" );
108
+ @ Override
109
+ public List <RuntimeClientPlugin > getClientPlugins () {
110
+ return ListUtils .of (
111
+ RuntimeClientPlugin .builder ()
112
+ .withConventions (AwsDependency .S3_MIDDLEWARE .dependency , "ValidateBucketName" ,
113
+ HAS_MIDDLEWARE )
114
+ .servicePredicate ((m , s ) -> testServiceId (s ))
115
+ .build (),
116
+ RuntimeClientPlugin .builder ()
117
+ .withConventions (AwsDependency .S3_MIDDLEWARE .dependency , "UseRegionalEndpoint" ,
118
+ HAS_MIDDLEWARE )
119
+ .servicePredicate ((m , s ) -> testServiceId (s ))
120
+ .build (),
121
+ RuntimeClientPlugin .builder ()
122
+ .withConventions (AwsDependency .ADD_EXPECT_CONTINUE .dependency , "AddExpectContinue" ,
123
+ HAS_MIDDLEWARE )
124
+ .servicePredicate ((m , s ) -> testServiceId (s ))
125
+ .build (),
126
+ RuntimeClientPlugin .builder ()
127
+ .withConventions (AwsDependency .SSEC_MIDDLEWARE .dependency , "Ssec" , HAS_MIDDLEWARE )
128
+ .operationPredicate ((m , s , o ) -> testInputContainsMember (m , o , SSEC_OPERATIONS )
129
+ && testServiceId (s ))
130
+ .build (),
131
+ RuntimeClientPlugin .builder ()
132
+ .withConventions (AwsDependency .LOCATION_CONSTRAINT .dependency , "LocationConstraint" ,
133
+ HAS_MIDDLEWARE )
134
+ .operationPredicate ((m , s , o ) -> o .getId ().getName ().equals ("CreateBucket" )
135
+ && testServiceId (s ))
136
+ .build (),
137
+ /**
138
+ * BUCKET_ENDPOINT_MIDDLEWARE needs two separate plugins. The first resolves the config in the client.
139
+ * The second applies the middleware to bucket endpoint operations.
140
+ */
141
+ RuntimeClientPlugin .builder ()
142
+ .withConventions (AwsDependency .BUCKET_ENDPOINT_MIDDLEWARE .dependency , "BucketEndpoint" ,
143
+ HAS_CONFIG )
144
+ .servicePredicate ((m , s ) -> testServiceId (s ))
145
+ .build (),
146
+ RuntimeClientPlugin .builder ()
147
+ .withConventions (AwsDependency .BUCKET_ENDPOINT_MIDDLEWARE .dependency , "BucketEndpoint" ,
148
+ HAS_MIDDLEWARE )
149
+ .operationPredicate ((m , s , o ) -> !NON_BUCKET_ENDPOINT_OPERATIONS .contains (o .getId ().getName ())
150
+ && testServiceId (s ))
151
+ .build (),
152
+ RuntimeClientPlugin .builder ()
153
+ .withConventions (AwsDependency .BODY_CHECKSUM .dependency , "ApplyMd5BodyChecksum" ,
154
+ HAS_MIDDLEWARE )
155
+ .operationPredicate ((m , s , o ) -> S3_MD5_OPERATIONS .contains (o .getId ().getName ())
156
+ && testServiceId (s ))
157
+ .build ()
158
+ );
159
+ }
160
+
161
+ private static boolean testInputContainsMember (
162
+ Model model ,
163
+ OperationShape operationShape ,
164
+ Set <String > expectedMemberNames
165
+ ) {
166
+ OperationIndex operationIndex = OperationIndex .of (model );
167
+ return operationIndex .getInput (operationShape )
168
+ .filter (input -> input .getMemberNames ().stream ().anyMatch (expectedMemberNames ::contains ))
169
+ .isPresent ();
170
+ }
171
+
172
+ private static boolean testServiceId (Shape serviceShape ) {
173
+ return serviceShape .getTrait (ServiceTrait .class ).map (ServiceTrait ::getSdkId ).orElse ("" ).equals ("S3" );
83
174
}
84
175
}
0 commit comments