Skip to content

Commit e718b19

Browse files
authored
Merge pull request #980 from aws/zoewang/outposts-merging
merge outposts
2 parents 7b35301 + 301bc12 commit e718b19

File tree

73 files changed

+5320
-605
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+5320
-605
lines changed

codegen/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@
7272
<artifactId>auth</artifactId>
7373
<version>${awsjavasdk.version}</version>
7474
</dependency>
75+
<dependency>
76+
<groupId>software.amazon.awssdk</groupId>
77+
<artifactId>arns</artifactId>
78+
<version>${awsjavasdk.version}</version>
79+
</dependency>
7580
<dependency>
7681
<artifactId>sdk-core</artifactId>
7782
<groupId>software.amazon.awssdk</groupId>

codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@ public class CustomizationConfig {
165165
*/
166166
private boolean enableEndpointDiscoveryMethodRequired = false;
167167

168+
/**
169+
* Arnable fields used in s3 control
170+
*/
171+
private Map<String, S3ArnableFieldConfig> s3ArnableFields;
168172
/**
169173
* Allow a customer to set an endpoint override AND bypass endpoint discovery on their client even when endpoint discovery
170174
* enabled is true and endpoint discovery is required for an operation. This customization should almost never be "true"
@@ -428,6 +432,19 @@ public void setEnableEndpointDiscoveryMethodRequired(boolean enableEndpointDisco
428432
this.enableEndpointDiscoveryMethodRequired = enableEndpointDiscoveryMethodRequired;
429433
}
430434

435+
public Map<String, S3ArnableFieldConfig> getS3ArnableFields() {
436+
return s3ArnableFields;
437+
}
438+
439+
public CustomizationConfig withS3ArnableFields(Map<String, S3ArnableFieldConfig> s3ArnableFields) {
440+
this.s3ArnableFields = s3ArnableFields;
441+
return this;
442+
}
443+
444+
public void setS3ArnableFields(Map<String, S3ArnableFieldConfig> s3ArnableFields) {
445+
this.s3ArnableFields = s3ArnableFields;
446+
}
447+
431448
public boolean allowEndpointOverrideForEndpointDiscoveryRequiredOperations() {
432449
return allowEndpointOverrideForEndpointDiscoveryRequiredOperations;
433450
}
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.codegen.model.config.customization;
17+
18+
import java.util.Map;
19+
20+
/**
21+
* Indicating a field that can be an ARN
22+
*/
23+
public class S3ArnableFieldConfig {
24+
private String field;
25+
26+
private String arnConverterFqcn;
27+
28+
private String arnResourceFqcn;
29+
30+
/**
31+
* The ARN field to be substituted set the value from the getter
32+
*/
33+
private String arnResourceSubstitutionGetter;
34+
35+
private String baseArnResourceFqcn;
36+
37+
private String executionAttributeKeyFqcn;
38+
39+
private String executionAttributeValueFqcn;
40+
41+
/**
42+
* Contains the fields that need to be populated if null from the getter methods.
43+
*
44+
* The key is the field name and the value is the getter method in ARN which supplies the value
45+
*/
46+
private Map<String, String> otherFieldsToPopulate;
47+
48+
public String getField() {
49+
return field;
50+
}
51+
52+
/**
53+
* Sets the field
54+
*
55+
* @param field The new field value.
56+
* @return This object for method chaining.
57+
*/
58+
public S3ArnableFieldConfig setField(String field) {
59+
this.field = field;
60+
return this;
61+
}
62+
63+
/**
64+
* @return the FQCN of the ArnConverter
65+
*/
66+
public String getArnConverterFqcn() {
67+
return arnConverterFqcn;
68+
}
69+
70+
/**
71+
* Sets the arnConverterFqcn
72+
*
73+
* @param arnConverterFqcn The new arnConverterFqcn value.
74+
* @return This object for method chaining.
75+
*/
76+
public S3ArnableFieldConfig setArnConverterFqcn(String arnConverterFqcn) {
77+
this.arnConverterFqcn = arnConverterFqcn;
78+
return this;
79+
}
80+
81+
public String getArnResourceFqcn() {
82+
return arnResourceFqcn;
83+
}
84+
85+
/**
86+
* Sets the arnResourceFqcn
87+
*
88+
* @param arnResourceFqcn The new arnResourceFqcn value.
89+
* @return This object for method chaining.
90+
*/
91+
public S3ArnableFieldConfig setArnResourceFqcn(String arnResourceFqcn) {
92+
this.arnResourceFqcn = arnResourceFqcn;
93+
return this;
94+
}
95+
96+
public String getArnResourceSubstitutionGetter() {
97+
return arnResourceSubstitutionGetter;
98+
}
99+
100+
/**
101+
* Sets the arnResourceSubstitutionGetter
102+
*
103+
* @param arnResourceSubstitutionGetter The new arnResourceSubstitutionGetter value.
104+
* @return This object for method chaining.
105+
*/
106+
public S3ArnableFieldConfig setArnResourceSubstitutionGetter(String arnResourceSubstitutionGetter) {
107+
this.arnResourceSubstitutionGetter = arnResourceSubstitutionGetter;
108+
return this;
109+
}
110+
111+
public Map<String, String> getOtherFieldsToPopulate() {
112+
return otherFieldsToPopulate;
113+
}
114+
115+
/**
116+
* Sets the substitionSetterToGetter
117+
*
118+
* @param substitionSetterToGetter The new substitionSetterToGetter value.
119+
* @return This object for method chaining.
120+
*/
121+
public S3ArnableFieldConfig setSubstitionSetterToGetter(Map<String, String> substitionSetterToGetter) {
122+
this.otherFieldsToPopulate = substitionSetterToGetter;
123+
return this;
124+
}
125+
126+
public String getBaseArnResourceFqcn() {
127+
return baseArnResourceFqcn;
128+
}
129+
130+
/**
131+
* Sets the baseArnResourceFqcn
132+
*
133+
* @param baseArnResourceFqcn The new baseArnResourceFqcn value.
134+
* @return This object for method chaining.
135+
*/
136+
public S3ArnableFieldConfig setBaseArnResourceFqcn(String baseArnResourceFqcn) {
137+
this.baseArnResourceFqcn = baseArnResourceFqcn;
138+
return this;
139+
}
140+
141+
public String getExecutionAttributeKeyFqcn() {
142+
return executionAttributeKeyFqcn;
143+
}
144+
145+
/**
146+
* Sets the executionAttributeKeyFqcn
147+
*
148+
* @param executionAttributeKeyFqcn The new executionAttributeKeyFqcn value.
149+
* @return This object for method chaining.
150+
*/
151+
public S3ArnableFieldConfig setExecutionAttributeKeyFqcn(String executionAttributeKeyFqcn) {
152+
this.executionAttributeKeyFqcn = executionAttributeKeyFqcn;
153+
return this;
154+
}
155+
156+
public String getExecutionAttributeValueFqcn() {
157+
return executionAttributeValueFqcn;
158+
}
159+
160+
/**
161+
* Sets the executionAttributeValueFqcn
162+
*
163+
* @param executionAttributeValueFqcn The new executionAttributeValueFqcn value.
164+
* @return This object for method chaining.
165+
*/
166+
public S3ArnableFieldConfig setExecutionAttributeValueFqcn(String executionAttributeValueFqcn) {
167+
this.executionAttributeValueFqcn = executionAttributeValueFqcn;
168+
return this;
169+
}
170+
171+
/**
172+
* Sets the otherFieldsToPopulate
173+
*
174+
* @param otherFieldsToPopulate The new otherFieldsToPopulate value.
175+
* @return This object for method chaining.
176+
*/
177+
public S3ArnableFieldConfig setOtherFieldsToPopulate(Map<String, String> otherFieldsToPopulate) {
178+
this.otherFieldsToPopulate = otherFieldsToPopulate;
179+
return this;
180+
}
181+
}

codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ShapeModel.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ public Map<String, MemberModel> getMembersAsMap() {
428428
* Tries to find the member model associated with the given c2j member name from this shape
429429
* model. Returns the member model if present else returns null.
430430
*/
431-
private MemberModel tryFindMemberModelByC2jName(String memberC2jName, boolean ignoreCase) {
431+
public MemberModel tryFindMemberModelByC2jName(String memberC2jName, boolean ignoreCase) {
432432

433433
List<MemberModel> memberModels = getMembers();
434434
String expectedName = ignoreCase ? StringUtils.lowerCase(memberC2jName)

codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/AsyncClientClass.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static javax.lang.model.element.Modifier.FINAL;
2121
import static javax.lang.model.element.Modifier.PRIVATE;
2222
import static javax.lang.model.element.Modifier.STATIC;
23+
import static software.amazon.awssdk.codegen.poet.client.ClientClassUtils.addS3ArnableFieldCode;
2324
import static software.amazon.awssdk.codegen.poet.client.ClientClassUtils.applyPaginatorUserAgentMethod;
2425
import static software.amazon.awssdk.codegen.poet.client.ClientClassUtils.applySignerOverrideMethod;
2526
import static software.amazon.awssdk.codegen.poet.client.SyncClientClass.getProtocolSpecs;
@@ -248,8 +249,7 @@ protected MethodSpec.Builder operationBody(MethodSpec.Builder builder, Operation
248249
builder.addCode(ClientClassUtils.callApplySignerOverrideMethod(opModel));
249250
}
250251

251-
builder.addCode(ClientClassUtils.addEndpointTraitCode(opModel))
252-
.addCode(protocolSpec.responseHandler(model, opModel));
252+
builder.addCode(protocolSpec.responseHandler(model, opModel));
253253
protocolSpec.errorResponseHandler(opModel).ifPresent(builder::addCode);
254254
builder.addCode(eventToByteBufferPublisher(opModel));
255255

@@ -297,6 +297,9 @@ protected MethodSpec.Builder operationBody(MethodSpec.Builder builder, Operation
297297
builder.endControlFlow();
298298
}
299299

300+
addS3ArnableFieldCode(opModel, model).ifPresent(builder::addCode);
301+
builder.addCode(ClientClassUtils.addEndpointTraitCode(opModel));
302+
300303
builder.addCode(protocolSpec.asyncExecutionHandler(model, opModel))
301304
.endControlFlow()
302305
.beginControlFlow("catch ($T t)", Throwable.class);

codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/ClientClassUtils.java

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,26 @@
1515

1616
package software.amazon.awssdk.codegen.poet.client;
1717

18+
import static software.amazon.awssdk.codegen.poet.PoetUtils.classNameFromFqcn;
19+
1820
import com.squareup.javapoet.ClassName;
1921
import com.squareup.javapoet.CodeBlock;
2022
import com.squareup.javapoet.MethodSpec;
2123
import com.squareup.javapoet.ParameterSpec;
2224
import com.squareup.javapoet.ParameterizedTypeName;
2325
import com.squareup.javapoet.TypeName;
2426
import com.squareup.javapoet.TypeVariableName;
27+
import java.util.Map;
28+
import java.util.Optional;
2529
import java.util.function.Consumer;
2630
import java.util.stream.Collectors;
2731
import javax.lang.model.element.Modifier;
32+
import software.amazon.awssdk.arns.Arn;
2833
import software.amazon.awssdk.auth.signer.EventStreamAws4Signer;
2934
import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
35+
import software.amazon.awssdk.codegen.model.config.customization.S3ArnableFieldConfig;
3036
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
37+
import software.amazon.awssdk.codegen.model.intermediate.MemberModel;
3138
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
3239
import software.amazon.awssdk.codegen.model.intermediate.ShapeModel;
3340
import software.amazon.awssdk.codegen.model.service.HostPrefixProcessor;
@@ -36,6 +43,7 @@
3643
import software.amazon.awssdk.core.ApiName;
3744
import software.amazon.awssdk.core.signer.Signer;
3845
import software.amazon.awssdk.core.util.VersionInfo;
46+
import software.amazon.awssdk.utils.HostnameValidator;
3947
import software.amazon.awssdk.utils.StringUtils;
4048
import software.amazon.awssdk.utils.Validate;
4149

@@ -177,9 +185,10 @@ static CodeBlock addEndpointTraitCode(OperationModel opModel) {
177185
builder.addStatement("String resolvedHostExpression = $S", processor.hostWithStringSpecifier());
178186
} else {
179187
processor.c2jNames()
180-
.forEach(name -> builder.addStatement("$T.paramNotBlank($L, $S)", Validate.class,
181-
inputShapeMemberGetter(opModel, name),
182-
name));
188+
.forEach(name -> builder.addStatement("$T.validateHostnameCompliant($L, $S, $S)",
189+
HostnameValidator.class,
190+
inputShapeMemberGetter(opModel, name),
191+
name, opModel.getInput().getVariableName()));
183192

184193
builder.addStatement("String resolvedHostExpression = String.format($S, $L)",
185194
processor.hostWithStringSpecifier(),
@@ -192,6 +201,73 @@ static CodeBlock addEndpointTraitCode(OperationModel opModel) {
192201
return builder.build();
193202
}
194203

204+
static Optional<CodeBlock> addS3ArnableFieldCode(OperationModel opModel, IntermediateModel model) {
205+
CodeBlock.Builder builder = CodeBlock.builder();
206+
Map<String, S3ArnableFieldConfig> s3ArnableFields = model.getCustomizationConfig().getS3ArnableFields();
207+
208+
if (s3ArnableFields != null &&
209+
s3ArnableFields.containsKey(opModel.getInputShape().getShapeName())) {
210+
S3ArnableFieldConfig s3ArnableField = s3ArnableFields.get(opModel.getInputShape().getShapeName());
211+
String fieldName = s3ArnableField.getField();
212+
MemberModel arnableMember = opModel.getInputShape().tryFindMemberModelByC2jName(fieldName, true);
213+
ClassName arnResourceFqcn = classNameFromFqcn(s3ArnableField.getArnResourceFqcn());
214+
215+
builder.addStatement("String $N = $N.$N()", fieldName,
216+
opModel.getInput().getVariableName(), arnableMember.getFluentGetterMethodName());
217+
builder.addStatement("$T arn = null", Arn.class);
218+
builder.beginControlFlow("if ($N != null && $N.startsWith(\"arn:\"))", fieldName, fieldName)
219+
.addStatement("arn = $T.fromString($N)", Arn.class, fieldName)
220+
.addStatement("$T s3Resource = $T.getInstance().convertArn(arn)",
221+
classNameFromFqcn(s3ArnableField.getBaseArnResourceFqcn()),
222+
classNameFromFqcn(s3ArnableField.getArnConverterFqcn()))
223+
.beginControlFlow("if (!(s3Resource instanceof $T))", arnResourceFqcn)
224+
.addStatement("throw new $T(String.format(\"Unsupported ARN type: %s\", s3Resource.type()))",
225+
IllegalArgumentException.class)
226+
.endControlFlow()
227+
.addStatement("$T resource = ($T) s3Resource", arnResourceFqcn, arnResourceFqcn);
228+
229+
Map<String, String> otherFieldsToPopulate = s3ArnableField.getOtherFieldsToPopulate();
230+
231+
for (Map.Entry<String, String> entry : otherFieldsToPopulate.entrySet()) {
232+
MemberModel memberModel = opModel.getInputShape().tryFindMemberModelByC2jName(entry.getKey(), true);
233+
String variableName = memberModel.getVariable().getVariableName();
234+
String arnVariableName = variableName + "InArn";
235+
builder.addStatement("String $N = $N.$N()", variableName,
236+
opModel.getInput().getVariableName(),
237+
memberModel.getFluentGetterMethodName());
238+
builder.addStatement("String $N = resource.$N",
239+
arnVariableName,
240+
entry.getValue());
241+
builder.beginControlFlow("if ($N != null && !$N.equals($N))",
242+
variableName,
243+
variableName,
244+
arnVariableName)
245+
.addStatement("throw new $T(String.format(\"%s field provided from the request (%s) is different from "
246+
+ "the one in the ARN (%s)\", $S, $N, $N))",
247+
IllegalArgumentException.class,
248+
variableName,
249+
variableName, arnVariableName)
250+
.endControlFlow();
251+
}
252+
253+
builder.add("$N = $N.toBuilder().$N(resource.$N())",
254+
opModel.getInput().getVariableName(),
255+
opModel.getInput().getVariableName(),
256+
arnableMember.getFluentSetterMethodName(),
257+
s3ArnableField.getArnResourceSubstitutionGetter());
258+
259+
for (Map.Entry<String, String> entry : otherFieldsToPopulate.entrySet()) {
260+
MemberModel memberModel = opModel.getInputShape().tryFindMemberModelByC2jName(entry.getKey(), true);
261+
String variableName = memberModel.getVariable().getVariableName();
262+
String arnVariableName = variableName + "InArn";
263+
builder.add(".$N($N)", memberModel.getFluentSetterMethodName(), arnVariableName);
264+
}
265+
266+
return Optional.of(builder.addStatement(".build()").endControlFlow().build());
267+
}
268+
return Optional.empty();
269+
}
270+
195271
/**
196272
* Given operation and c2j name, returns the String that represents calling the
197273
* c2j member's getter method in the opmodel input shape.

0 commit comments

Comments
 (0)