Skip to content

Commit 575d7cd

Browse files
committed
Improve comments/naming + fix generated class test
1 parent 5b94b13 commit 575d7cd

5 files changed

Lines changed: 215 additions & 25 deletions

File tree

codegen/src/main/java/software/amazon/awssdk/codegen/jmespath/parser/JmesPathParser.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -251,17 +251,16 @@ private ParseResult<IndexExpression> parseIndexExpressionWithLhsExpression(int s
251251
// e.g., listOfUnions[*][string, object.key][] should parse as:
252252
// - left: listOfUnions[*][string, object.key]
253253
// - right: []
254-
// This allows the left side to be recursively parsed as another index expression
254+
// This allows both the left and right side to be recursively parsed
255255
for (int i = bracketPositions.size() - 1; i >= 0; i--) {
256256
Integer bracketPosition = bracketPositions.get(i);
257257
ParseResult<Expression> leftSide = parseExpression(startPosition, bracketPosition);
258258
if (!leftSide.hasResult()) {
259259
continue;
260260
}
261261

262-
// Use the special bracket specifier parser that supports multi-select-lists
263-
// This is safe here because we know there's a left-hand expression
264-
ParseResult<BracketSpecifier> rightSide = parseBracketSpecifierWithMultiSelect(bracketPosition, endPosition);
262+
// we know there is a left hand expression and that the Rhs is a bracketSpecifier
263+
ParseResult<BracketSpecifier> rightSide = parseBracketSpecifierWithLhsExpression(bracketPosition, endPosition);
265264
if (!rightSide.hasResult()) {
266265
continue;
267266
}
@@ -488,11 +487,10 @@ private ParseResult<BracketSpecifier> parseBracketSpecifier(int startPosition, i
488487
}
489488

490489
/**
490+
* This is a special case for bracket specifiers with a left-hand expression and which can contain multi-select-lists.
491491
* bracket-specifier-with-multiselect = "[" multi-select-list-content "]"
492-
* This is a special case for bracket specifiers that can contain multi-select-lists,
493-
* only used when there's a left-hand expression (to avoid conflicting with standalone multi-select-lists).
494492
*/
495-
private ParseResult<BracketSpecifier> parseBracketSpecifierWithMultiSelect(int startPosition, int endPosition) {
493+
private ParseResult<BracketSpecifier> parseBracketSpecifierWithLhsExpression(int startPosition, int endPosition) {
496494
startPosition = trimLeftWhitespace(startPosition, endPosition);
497495
endPosition = trimRightWhitespace(startPosition, endPosition);
498496

codegen/src/test/java/software/amazon/awssdk/codegen/jmespath/JmesPathParserTest.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,32 +43,32 @@ public void testSubExpressionWithMultiSelectList() {
4343
public void testSubExpressionWithMultiSelectListAndFlatten() {
4444
Expression expression = JmesPathParser.parse("listOfUnions[*][string, object.key][]");
4545

46-
// The expression should be: listOfUnions[*][string, object.key][]
47-
// Parsed as: IndexExpression(IndexExpression(IndexExpression(listOfUnions, [*]), [string, object.key]), [])
46+
// The expression should be parsed as:
47+
// IndexExpression(IndexExpression(IndexExpression(listOfUnions, [*]), [string, object.key]), [])
4848
assertThat(expression.isIndexExpression()).isTrue();
4949

50-
// Outermost: []
50+
// the right most flatten
5151
assertThat(expression.asIndexExpression().bracketSpecifier().isBracketSpecifierWithoutContents()).isTrue();
5252

5353
// Middle: [string, object.key]
54-
Expression middleExpr = expression.asIndexExpression().expression().get();
55-
assertThat(middleExpr.isIndexExpression()).isTrue();
56-
assertThat(middleExpr.asIndexExpression().bracketSpecifier().isBracketSpecifierWithContents()).isTrue();
57-
assertThat(middleExpr.asIndexExpression().bracketSpecifier().asBracketSpecifierWithContents().isMultiSelectList()).isTrue();
54+
Expression middleBracketsExpr = expression.asIndexExpression().expression().get();
55+
assertThat(middleBracketsExpr.isIndexExpression()).isTrue();
56+
assertThat(middleBracketsExpr.asIndexExpression().bracketSpecifier().isBracketSpecifierWithContents()).isTrue();
57+
assertThat(middleBracketsExpr.asIndexExpression().bracketSpecifier().asBracketSpecifierWithContents().isMultiSelectList()).isTrue();
5858

59-
MultiSelectList multiSelectList = middleExpr.asIndexExpression().bracketSpecifier()
59+
MultiSelectList multiSelectList = middleBracketsExpr.asIndexExpression().bracketSpecifier()
6060
.asBracketSpecifierWithContents().asMultiSelectList();
6161
assertThat(multiSelectList.expressions()).hasSize(2);
6262
assertThat(multiSelectList.expressions().get(0).asIdentifier()).isEqualTo("string");
6363
assertThat(multiSelectList.expressions().get(1).asSubExpression().leftExpression().asIdentifier()).isEqualTo("object");
6464
assertThat(multiSelectList.expressions().get(1).asSubExpression().rightSubExpression().asIdentifier()).isEqualTo("key");
6565

66-
// Innermost: listOfUnions[*]
67-
Expression innerExpr = middleExpr.asIndexExpression().expression().get();
68-
assertThat(innerExpr.isIndexExpression()).isTrue();
69-
assertThat(innerExpr.asIndexExpression().expression().get().asIdentifier()).isEqualTo("listOfUnions");
70-
assertThat(innerExpr.asIndexExpression().bracketSpecifier().isBracketSpecifierWithContents()).isTrue();
71-
assertThat(innerExpr.asIndexExpression().bracketSpecifier().asBracketSpecifierWithContents().isWildcardExpression()).isTrue();
66+
// left most wildcard: listOfUnions[*]
67+
Expression wildCardExpr = middleBracketsExpr.asIndexExpression().expression().get();
68+
assertThat(wildCardExpr.isIndexExpression()).isTrue();
69+
assertThat(wildCardExpr.asIndexExpression().expression().get().asIdentifier()).isEqualTo("listOfUnions");
70+
assertThat(wildCardExpr.asIndexExpression().bracketSpecifier().isBracketSpecifierWithContents()).isTrue();
71+
assertThat(wildCardExpr.asIndexExpression().bracketSpecifier().asBracketSpecifierWithContents().isWildcardExpression()).isTrue();
7272
}
7373

7474
@Test

codegen/src/test/java/software/amazon/awssdk/codegen/poet/PoetMatchers.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ private static String getExpectedClass(ClassSpec spec, String testFile, boolean
9595
}
9696
}
9797

98-
public static String generateClass(ClassSpec spec) {
98+
private static String generateClass(ClassSpec spec) {
9999
StringBuilder output = new StringBuilder();
100100
try {
101101
buildJavaFile(spec).writeTo(output);

codegen/src/test/java/software/amazon/awssdk/codegen/poet/rules/EndpointResolverInterceptorSpecTest.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
package software.amazon.awssdk.codegen.poet.rules;
1717

1818
import static org.hamcrest.MatcherAssert.assertThat;
19-
import static software.amazon.awssdk.codegen.poet.PoetMatchers.generateClass;
2019
import static software.amazon.awssdk.codegen.poet.PoetMatchers.generatesTo;
2120

2221
import org.junit.jupiter.api.Test;
@@ -51,7 +50,6 @@ void endpointResolverInterceptorClassWithEndpointBasedAuth() {
5150
@Test
5251
public void endpointProviderTestClassWithStringArray() {
5352
ClassSpec endpointProviderInterceptor = new EndpointResolverInterceptorSpec(ClientTestModels.stringArrayServiceModels());
54-
// assertThat(endpointProviderSpec, generatesTo("endpoint-rules-stringarray-test-class.java"));
55-
System.out.println(generateClass(endpointProviderInterceptor));
53+
assertThat(endpointProviderInterceptor, generatesTo("endpoint-resolve-interceptor-with-stringarray.java"));
5654
}
5755
}
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
package software.amazon.awssdk.services.samplesvc.endpoints.internal;
2+
3+
import java.time.Duration;
4+
import java.util.Arrays;
5+
import java.util.List;
6+
import java.util.Optional;
7+
import java.util.concurrent.CompletionException;
8+
import software.amazon.awssdk.annotations.Generated;
9+
import software.amazon.awssdk.annotations.SdkInternalApi;
10+
import software.amazon.awssdk.awscore.AwsExecutionAttribute;
11+
import software.amazon.awssdk.awscore.endpoints.AwsEndpointAttribute;
12+
import software.amazon.awssdk.awscore.endpoints.authscheme.EndpointAuthScheme;
13+
import software.amazon.awssdk.awscore.endpoints.authscheme.SigV4AuthScheme;
14+
import software.amazon.awssdk.awscore.endpoints.authscheme.SigV4aAuthScheme;
15+
import software.amazon.awssdk.core.SdkRequest;
16+
import software.amazon.awssdk.core.SelectedAuthScheme;
17+
import software.amazon.awssdk.core.exception.SdkClientException;
18+
import software.amazon.awssdk.core.interceptor.Context;
19+
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
20+
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
21+
import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute;
22+
import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute;
23+
import software.amazon.awssdk.core.metrics.CoreMetric;
24+
import software.amazon.awssdk.endpoints.Endpoint;
25+
import software.amazon.awssdk.http.SdkHttpRequest;
26+
import software.amazon.awssdk.http.auth.aws.signer.AwsV4HttpSigner;
27+
import software.amazon.awssdk.http.auth.aws.signer.AwsV4aHttpSigner;
28+
import software.amazon.awssdk.http.auth.aws.signer.RegionSet;
29+
import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption;
30+
import software.amazon.awssdk.identity.spi.Identity;
31+
import software.amazon.awssdk.metrics.MetricCollector;
32+
import software.amazon.awssdk.services.samplesvc.endpoints.SampleSvcEndpointParams;
33+
import software.amazon.awssdk.services.samplesvc.endpoints.SampleSvcEndpointProvider;
34+
import software.amazon.awssdk.services.samplesvc.jmespath.internal.JmesPathRuntime;
35+
import software.amazon.awssdk.services.samplesvc.model.ListOfObjectsOperationRequest;
36+
import software.amazon.awssdk.utils.CollectionUtils;
37+
38+
@Generated("software.amazon.awssdk:codegen")
39+
@SdkInternalApi
40+
public final class SampleSvcResolveEndpointInterceptor implements ExecutionInterceptor {
41+
@Override
42+
public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) {
43+
SdkRequest result = context.request();
44+
if (AwsEndpointProviderUtils.endpointIsDiscovered(executionAttributes)) {
45+
return result;
46+
}
47+
SampleSvcEndpointProvider provider = (SampleSvcEndpointProvider) executionAttributes
48+
.getAttribute(SdkInternalExecutionAttribute.ENDPOINT_PROVIDER);
49+
try {
50+
long resolveEndpointStart = System.nanoTime();
51+
SampleSvcEndpointParams endpointParams = ruleParams(result, executionAttributes);
52+
Endpoint endpoint = provider.resolveEndpoint(endpointParams).join();
53+
Duration resolveEndpointDuration = Duration.ofNanos(System.nanoTime() - resolveEndpointStart);
54+
Optional<MetricCollector> metricCollector = executionAttributes
55+
.getOptionalAttribute(SdkExecutionAttribute.API_CALL_METRIC_COLLECTOR);
56+
metricCollector.ifPresent(mc -> mc.reportMetric(CoreMetric.ENDPOINT_RESOLVE_DURATION, resolveEndpointDuration));
57+
if (!AwsEndpointProviderUtils.disableHostPrefixInjection(executionAttributes)) {
58+
Optional<String> hostPrefix = hostPrefix(executionAttributes.getAttribute(SdkExecutionAttribute.OPERATION_NAME),
59+
result);
60+
if (hostPrefix.isPresent()) {
61+
endpoint = AwsEndpointProviderUtils.addHostPrefix(endpoint, hostPrefix.get());
62+
}
63+
}
64+
List<EndpointAuthScheme> endpointAuthSchemes = endpoint.attribute(AwsEndpointAttribute.AUTH_SCHEMES);
65+
SelectedAuthScheme<?> selectedAuthScheme = executionAttributes
66+
.getAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME);
67+
if (endpointAuthSchemes != null && selectedAuthScheme != null) {
68+
selectedAuthScheme = authSchemeWithEndpointSignerProperties(endpointAuthSchemes, selectedAuthScheme);
69+
executionAttributes.putAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME, selectedAuthScheme);
70+
}
71+
executionAttributes.putAttribute(SdkInternalExecutionAttribute.RESOLVED_ENDPOINT, endpoint);
72+
setMetricValues(endpoint, executionAttributes);
73+
return result;
74+
} catch (CompletionException e) {
75+
Throwable cause = e.getCause();
76+
if (cause instanceof SdkClientException) {
77+
throw (SdkClientException) cause;
78+
} else {
79+
throw SdkClientException.create("Endpoint resolution failed", cause);
80+
}
81+
}
82+
}
83+
84+
@Override
85+
public SdkHttpRequest modifyHttpRequest(Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes) {
86+
Endpoint resolvedEndpoint = executionAttributes.getAttribute(SdkInternalExecutionAttribute.RESOLVED_ENDPOINT);
87+
if (resolvedEndpoint.headers().isEmpty()) {
88+
return context.httpRequest();
89+
}
90+
SdkHttpRequest.Builder httpRequestBuilder = context.httpRequest().toBuilder();
91+
resolvedEndpoint.headers().forEach((name, values) -> {
92+
values.forEach(v -> httpRequestBuilder.appendHeader(name, v));
93+
});
94+
return httpRequestBuilder.build();
95+
}
96+
97+
public static SampleSvcEndpointParams ruleParams(SdkRequest request, ExecutionAttributes executionAttributes) {
98+
SampleSvcEndpointParams.Builder builder = SampleSvcEndpointParams.builder();
99+
setContextParams(builder, executionAttributes.getAttribute(AwsExecutionAttribute.OPERATION_NAME), request);
100+
setStaticContextParams(builder, executionAttributes.getAttribute(AwsExecutionAttribute.OPERATION_NAME));
101+
setOperationContextParams(builder, executionAttributes.getAttribute(AwsExecutionAttribute.OPERATION_NAME), request);
102+
return builder.build();
103+
}
104+
105+
private static void setContextParams(SampleSvcEndpointParams.Builder params, String operationName, SdkRequest request) {
106+
}
107+
108+
private static void setStaticContextParams(SampleSvcEndpointParams.Builder params, String operationName) {
109+
switch (operationName) {
110+
case "EmptyStaticContextOperation":
111+
emptyStaticContextOperationStaticContextParams(params);
112+
break;
113+
case "StaticContextOperation":
114+
staticContextOperationStaticContextParams(params);
115+
break;
116+
default:
117+
break;
118+
}
119+
}
120+
121+
private static void emptyStaticContextOperationStaticContextParams(SampleSvcEndpointParams.Builder params) {
122+
params.stringArrayParam(Arrays.asList());
123+
}
124+
125+
private static void staticContextOperationStaticContextParams(SampleSvcEndpointParams.Builder params) {
126+
params.stringArrayParam(Arrays.asList("staticValue1"));
127+
}
128+
129+
private <T extends Identity> SelectedAuthScheme<T> authSchemeWithEndpointSignerProperties(
130+
List<EndpointAuthScheme> endpointAuthSchemes, SelectedAuthScheme<T> selectedAuthScheme) {
131+
for (EndpointAuthScheme endpointAuthScheme : endpointAuthSchemes) {
132+
if (!endpointAuthScheme.schemeId().equals(selectedAuthScheme.authSchemeOption().schemeId())) {
133+
continue;
134+
}
135+
AuthSchemeOption.Builder option = selectedAuthScheme.authSchemeOption().toBuilder();
136+
if (endpointAuthScheme instanceof SigV4AuthScheme) {
137+
SigV4AuthScheme v4AuthScheme = (SigV4AuthScheme) endpointAuthScheme;
138+
if (v4AuthScheme.isDisableDoubleEncodingSet()) {
139+
option.putSignerProperty(AwsV4HttpSigner.DOUBLE_URL_ENCODE, !v4AuthScheme.disableDoubleEncoding());
140+
}
141+
if (v4AuthScheme.signingRegion() != null) {
142+
option.putSignerProperty(AwsV4HttpSigner.REGION_NAME, v4AuthScheme.signingRegion());
143+
}
144+
if (v4AuthScheme.signingName() != null) {
145+
option.putSignerProperty(AwsV4HttpSigner.SERVICE_SIGNING_NAME, v4AuthScheme.signingName());
146+
}
147+
return new SelectedAuthScheme<>(selectedAuthScheme.identity(), selectedAuthScheme.signer(), option.build());
148+
}
149+
if (endpointAuthScheme instanceof SigV4aAuthScheme) {
150+
SigV4aAuthScheme v4aAuthScheme = (SigV4aAuthScheme) endpointAuthScheme;
151+
if (v4aAuthScheme.isDisableDoubleEncodingSet()) {
152+
option.putSignerProperty(AwsV4aHttpSigner.DOUBLE_URL_ENCODE, !v4aAuthScheme.disableDoubleEncoding());
153+
}
154+
if (!CollectionUtils.isNullOrEmpty(v4aAuthScheme.signingRegionSet())) {
155+
RegionSet regionSet = RegionSet.create(v4aAuthScheme.signingRegionSet());
156+
option.putSignerProperty(AwsV4aHttpSigner.REGION_SET, regionSet);
157+
}
158+
if (v4aAuthScheme.signingName() != null) {
159+
option.putSignerProperty(AwsV4aHttpSigner.SERVICE_SIGNING_NAME, v4aAuthScheme.signingName());
160+
}
161+
return new SelectedAuthScheme<>(selectedAuthScheme.identity(), selectedAuthScheme.signer(), option.build());
162+
}
163+
throw new IllegalArgumentException("Endpoint auth scheme '" + endpointAuthScheme.name()
164+
+ "' cannot be mapped to the SDK auth scheme. Was it declared in the service's model?");
165+
}
166+
return selectedAuthScheme;
167+
}
168+
169+
private static void setOperationContextParams(SampleSvcEndpointParams.Builder params, String operationName, SdkRequest request) {
170+
switch (operationName) {
171+
case "ListOfObjectsOperation":
172+
setOperationContextParams(params, (ListOfObjectsOperationRequest) request);
173+
break;
174+
default:
175+
break;
176+
}
177+
}
178+
179+
private static void setOperationContextParams(SampleSvcEndpointParams.Builder params, ListOfObjectsOperationRequest request) {
180+
JmesPathRuntime.Value input = new JmesPathRuntime.Value(request);
181+
params.stringArrayParam(input.field("nested").field("listOfObjects").wildcard().field("key").stringValues());
182+
}
183+
184+
private static Optional<String> hostPrefix(String operationName, SdkRequest request) {
185+
return Optional.empty();
186+
}
187+
188+
private void setMetricValues(Endpoint endpoint, ExecutionAttributes executionAttributes) {
189+
if (endpoint.attribute(AwsEndpointAttribute.METRIC_VALUES) != null) {
190+
executionAttributes.getOptionalAttribute(SdkInternalExecutionAttribute.BUSINESS_METRICS).ifPresent(
191+
metrics -> endpoint.attribute(AwsEndpointAttribute.METRIC_VALUES).forEach(v -> metrics.addMetric(v)));
192+
}
193+
}
194+
}

0 commit comments

Comments
 (0)