Skip to content

Commit e9a76d0

Browse files
committed
AWS/Query and EC2 unmarshaller support
1 parent 735632f commit e9a76d0

36 files changed

+1417
-292
lines changed

codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -223,20 +223,18 @@ private ParameterHttpMapping generateParameterHttpMapping(Shape parentShape,
223223
Shape memberShape = allC2jShapes.get(member.getShape());
224224
mapping.withLocation(Location.forValue(member.getLocation()))
225225
.withPayload(member.isPayload()).withStreaming(member.isStreaming())
226-
.withFlattened(isFlattened(member, protocol, memberShape))
227-
.withUnmarshallLocationName(deriveUnmarshallerLocationName(memberName, member))
226+
.withFlattened(isFlattened(member, memberShape))
227+
.withUnmarshallLocationName(deriveUnmarshallerLocationName(memberShape, memberName, member))
228228
.withMarshallLocationName(
229229
deriveMarshallerLocationName(memberShape, memberName, member, protocol))
230230
.withIsGreedy(isGreedy(parentShape, allC2jShapes, mapping));
231231

232232
return mapping;
233233
}
234234

235-
private boolean isFlattened(Member member, String protocol, Shape memberShape) {
235+
private boolean isFlattened(Member member, Shape memberShape) {
236236
return member.isFlattened()
237-
|| memberShape.isFlattened()
238-
// EC2 lists are always flattened
239-
|| (memberShape.getListMember() != null && protocol.equalsIgnoreCase("ec2"));
237+
|| memberShape.isFlattened();
240238
}
241239

242240
/**
@@ -272,9 +270,9 @@ private String findRequestUri(Shape parentShape, Map<String, Shape> allC2jShapes
272270
.findFirst().orElseThrow(() -> new RuntimeException("Could not find request URI for input shape"));
273271
}
274272

275-
private String deriveUnmarshallerLocationName(String memberName, Member member) {
276-
277-
final String locationName = member.getLocationName();
273+
private String deriveUnmarshallerLocationName(Shape memberShape, String memberName, Member member) {
274+
String locationName = memberShape.getListMember() != null && memberShape.isFlattened() ?
275+
memberShape.getListMember().getLocationName() : member.getLocationName();
278276

279277
if (locationName != null && !locationName.trim().isEmpty()) {
280278
return locationName;

codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/Ec2ProtocolSpec.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.squareup.javapoet.MethodSpec;
1919
import java.util.ArrayList;
2020
import java.util.List;
21+
import software.amazon.awssdk.awscore.protocol.query.AwsEc2ProtocolFactory;
2122
import software.amazon.awssdk.codegen.poet.PoetExtensions;
2223

2324
public class Ec2ProtocolSpec extends QueryXmlProtocolSpec {
@@ -36,6 +37,11 @@ public List<MethodSpec> additionalMethods() {
3637
return additionalMethods;
3738
}
3839

40+
@Override
41+
protected Class<?> protocolFactoryClass() {
42+
return AwsEc2ProtocolFactory.class;
43+
}
44+
3945
/*
4046
private MethodSpec dryRunMethod() {
4147
TypeVariableName typeVariableName = TypeVariableName.get("X", AmazonWebServiceRequest.class);

codegen/src/main/java/software/amazon/awssdk/codegen/poet/client/specs/QueryXmlProtocolSpec.java

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,8 @@
3131
import org.w3c.dom.Node;
3232
import software.amazon.awssdk.awscore.exception.AwsServiceException;
3333
import software.amazon.awssdk.awscore.http.response.DefaultErrorResponseHandler;
34-
import software.amazon.awssdk.awscore.http.response.StaxResponseHandler;
3534
import software.amazon.awssdk.awscore.protocol.query.AwsQueryProtocolFactory;
3635
import software.amazon.awssdk.awscore.protocol.xml.StandardErrorUnmarshaller;
37-
import software.amazon.awssdk.awscore.protocol.xml.StaxOperationMetadata;
3836
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
3937
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
4038
import software.amazon.awssdk.codegen.model.intermediate.ShapeModel;
@@ -61,7 +59,7 @@ public QueryXmlProtocolSpec(PoetExtensions poetExtensions) {
6159

6260
@Override
6361
public FieldSpec protocolFactory(IntermediateModel model) {
64-
return FieldSpec.builder(AwsQueryProtocolFactory.class, "protocolFactory")
62+
return FieldSpec.builder(protocolFactoryClass(), "protocolFactory")
6563
.addModifiers(Modifier.PRIVATE, Modifier.FINAL).build();
6664
}
6765

@@ -75,7 +73,7 @@ public List<FieldSpec> additionalFields() {
7573
@Override
7674
public MethodSpec initProtocolFactory(IntermediateModel model) {
7775
MethodSpec.Builder methodSpec = MethodSpec.methodBuilder("init")
78-
.returns(AwsQueryProtocolFactory.class)
76+
.returns(protocolFactoryClass())
7977
.addModifiers(Modifier.PRIVATE);
8078

8179
methodSpec.addStatement("$T<$T> unmarshallers = new $T<>()", List.class, unmarshallerType, ArrayList.class);
@@ -85,11 +83,15 @@ public MethodSpec initProtocolFactory(IntermediateModel model) {
8583
poetExtensions.getModelClass(model.getSdkModeledExceptionBaseClassName()))
8684
.build());
8785
methodSpec.addStatement("this.exceptionUnmarshallers = unmarshallers");
88-
methodSpec.addStatement("return new $T()", AwsQueryProtocolFactory.class);
86+
methodSpec.addStatement("return new $T()", protocolFactoryClass());
8987

9088
return methodSpec.build();
9189
}
9290

91+
protected Class<?> protocolFactoryClass() {
92+
return AwsQueryProtocolFactory.class;
93+
}
94+
9395
private ClassName getErrorUnmarshallerClass(IntermediateModel model) {
9496
return StringUtils.isNotBlank(model.getExceptionUnmarshallerImpl()) ?
9597
PoetUtils.classNameFromFqcn(model.getExceptionUnmarshallerImpl()) :
@@ -99,18 +101,13 @@ private ClassName getErrorUnmarshallerClass(IntermediateModel model) {
99101
@Override
100102
public CodeBlock responseHandler(IntermediateModel model,
101103
OperationModel opModel) {
102-
ClassName unmarshaller = poetExtensions.getTransformClass(opModel.getReturnType().getReturnType() + "Unmarshaller");
103104
ClassName responseType = poetExtensions.getModelClass(opModel.getReturnType().getReturnType());
104105

105106
return CodeBlock.builder()
106-
.addStatement("\n\n$T<$T> responseHandler = new $T<>(new $T(), new $T().withHasStreamingSuccessResponse"
107-
+ "($L))",
107+
.addStatement("\n\n$T<$T> responseHandler = protocolFactory.createResponseHandler($T::builder)",
108108
HttpResponseHandler.class,
109109
responseType,
110-
StaxResponseHandler.class,
111-
unmarshaller,
112-
StaxOperationMetadata.class,
113-
opModel.hasStreamingOutput())
110+
responseType)
114111
.build();
115112
}
116113

codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/AwsServiceModel.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,7 @@ public AwsServiceModel(IntermediateModel intermediateModel, ShapeModel shapeMode
7474
this.shapeModelSpec = new ShapeModelSpec(this.shapeModel,
7575
typeProvider,
7676
poetExtensions,
77-
intermediateModel.getNamingStrategy(),
78-
intermediateModel.getCustomizationConfig());
77+
intermediateModel);
7978
this.modelMethodOverrides = new ModelMethodOverrides(this.poetExtensions);
8079
this.modelBuilderSpecs = new ModelBuilderSpecs(intermediateModel, this.shapeModel, this.typeProvider);
8180
}

codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ShapeModelSpec.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
import java.util.stream.Collectors;
2828
import javax.lang.model.element.Modifier;
2929
import software.amazon.awssdk.codegen.model.config.customization.CustomizationConfig;
30+
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
3031
import software.amazon.awssdk.codegen.model.intermediate.MemberModel;
32+
import software.amazon.awssdk.codegen.model.intermediate.Protocol;
3133
import software.amazon.awssdk.codegen.model.intermediate.ShapeModel;
3234
import software.amazon.awssdk.codegen.model.intermediate.ShapeType;
3335
import software.amazon.awssdk.codegen.naming.NamingStrategy;
@@ -53,17 +55,18 @@ class ShapeModelSpec {
5355
private final PoetExtensions poetExtensions;
5456
private final NamingStrategy namingStrategy;
5557
private final CustomizationConfig customizationConfig;
58+
private final IntermediateModel model;
5659

5760
ShapeModelSpec(ShapeModel shapeModel,
5861
TypeProvider typeProvider,
5962
PoetExtensions poetExtensions,
60-
NamingStrategy namingStrategy,
61-
CustomizationConfig customizationConfig) {
63+
IntermediateModel model) {
6264
this.shapeModel = shapeModel;
6365
this.typeProvider = typeProvider;
6466
this.poetExtensions = poetExtensions;
65-
this.namingStrategy = namingStrategy;
66-
this.customizationConfig = customizationConfig;
67+
this.namingStrategy = model.getNamingStrategy();
68+
this.customizationConfig = model.getCustomizationConfig();
69+
this.model = model;
6770
}
6871

6972
ClassName className() {
@@ -186,16 +189,23 @@ private CodeBlock createTimestampFormatTrait(MemberModel m) {
186189
}
187190

188191
private CodeBlock createLocationTrait(MemberModel m) {
192+
String unmarshallLocation = unmarshallLocation(m);
189193
return CodeBlock.builder()
190194
// TODO will marshall and unmarshall location name ever differ?
191195
.add("$T.builder()\n"
192-
+ ".location($T.$L)"
193-
+ ".locationName($S)"
196+
+ ".location($T.$L)\n"
197+
+ ".locationName($S)\n"
198+
+ unmarshallLocation
194199
+ ".build()", ClassName.get(LocationTrait.class), ClassName.get(MarshallLocation.class),
195200
m.getHttp().getMarshallLocation(), m.getHttp().getMarshallLocationName())
196201
.build();
197202
}
198203

204+
private String unmarshallLocation(MemberModel m) {
205+
return model.getMetadata().getProtocol() == Protocol.EC2 ?
206+
String.format(".unmarshallLocationName(\"%s\")%n", m.getHttp().getUnmarshallLocationName()) : "";
207+
}
208+
199209
private CodeBlock createIdempotencyTrait() {
200210
return CodeBlock.builder()
201211
.add("$T.idempotencyToken()", ClassName.get(DefaultValueTrait.class))

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/client/test-query-client-class.java

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@
88
import software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler;
99
import software.amazon.awssdk.awscore.exception.AwsServiceException;
1010
import software.amazon.awssdk.awscore.http.response.DefaultErrorResponseHandler;
11-
import software.amazon.awssdk.awscore.http.response.StaxResponseHandler;
1211
import software.amazon.awssdk.awscore.protocol.query.AwsQueryProtocolFactory;
1312
import software.amazon.awssdk.awscore.protocol.xml.StandardErrorUnmarshaller;
14-
import software.amazon.awssdk.awscore.protocol.xml.StaxOperationMetadata;
1513
import software.amazon.awssdk.core.client.config.SdkClientConfiguration;
1614
import software.amazon.awssdk.core.client.handler.ClientExecutionParams;
1715
import software.amazon.awssdk.core.client.handler.SyncClientHandler;
@@ -25,9 +23,7 @@
2523
import software.amazon.awssdk.services.query.model.InvalidInputException;
2624
import software.amazon.awssdk.services.query.model.QueryException;
2725
import software.amazon.awssdk.services.query.transform.APostOperationRequestMarshaller;
28-
import software.amazon.awssdk.services.query.transform.APostOperationResponseUnmarshaller;
2926
import software.amazon.awssdk.services.query.transform.APostOperationWithOutputRequestMarshaller;
30-
import software.amazon.awssdk.services.query.transform.APostOperationWithOutputResponseUnmarshaller;
3127
import software.amazon.awssdk.services.query.transform.InvalidInputExceptionUnmarshaller;
3228

3329
/**
@@ -81,8 +77,8 @@ public final String serviceName() {
8177
public APostOperationResponse aPostOperation(APostOperationRequest aPostOperationRequest) throws InvalidInputException,
8278
AwsServiceException, SdkClientException, QueryException {
8379

84-
HttpResponseHandler<APostOperationResponse> responseHandler = new StaxResponseHandler<>(
85-
new APostOperationResponseUnmarshaller(), new StaxOperationMetadata().withHasStreamingSuccessResponse(false));
80+
HttpResponseHandler<APostOperationResponse> responseHandler = protocolFactory
81+
.createResponseHandler(APostOperationResponse::builder);
8682

8783
DefaultErrorResponseHandler errorResponseHandler = new DefaultErrorResponseHandler(exceptionUnmarshallers);
8884

@@ -116,9 +112,8 @@ public APostOperationWithOutputResponse aPostOperationWithOutput(
116112
APostOperationWithOutputRequest aPostOperationWithOutputRequest) throws InvalidInputException, AwsServiceException,
117113
SdkClientException, QueryException {
118114

119-
HttpResponseHandler<APostOperationWithOutputResponse> responseHandler = new StaxResponseHandler<>(
120-
new APostOperationWithOutputResponseUnmarshaller(),
121-
new StaxOperationMetadata().withHasStreamingSuccessResponse(false));
115+
HttpResponseHandler<APostOperationWithOutputResponse> responseHandler = protocolFactory
116+
.createResponseHandler(APostOperationWithOutputResponse::builder);
122117

123118
DefaultErrorResponseHandler errorResponseHandler = new DefaultErrorResponseHandler(exceptionUnmarshallers);
124119

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright 2010-2018 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.awscore.http.response;
17+
18+
import java.util.function.Function;
19+
import software.amazon.awssdk.annotations.SdkProtectedApi;
20+
import software.amazon.awssdk.awscore.AwsResponse;
21+
import software.amazon.awssdk.core.SdkStandardLogger;
22+
import software.amazon.awssdk.core.http.HttpResponseHandler;
23+
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
24+
import software.amazon.awssdk.core.internal.protocol.query.unmarshall.QueryProtocolUnmarshaller;
25+
import software.amazon.awssdk.core.protocol.SdkPojo;
26+
import software.amazon.awssdk.http.SdkHttpFullResponse;
27+
28+
/**
29+
* Default implementation of HttpResponseHandler that handles a successful
30+
* response from an AWS service and unmarshalls the result using a StAX
31+
* unmarshaller.
32+
*
33+
* @param <T> Indicates the type being unmarshalled by this response handler.
34+
*/
35+
@SdkProtectedApi
36+
// TODO rename
37+
public final class NewStaxResponseHandler<T extends AwsResponse> implements HttpResponseHandler<T> {
38+
39+
private final QueryProtocolUnmarshaller<T> unmarshaller;
40+
private final Function<SdkHttpFullResponse, SdkPojo> pojoSupplier;
41+
42+
43+
public NewStaxResponseHandler(QueryProtocolUnmarshaller<T> unmarshaller,
44+
Function<SdkHttpFullResponse, SdkPojo> pojoSupplier) {
45+
this.unmarshaller = unmarshaller;
46+
this.pojoSupplier = pojoSupplier;
47+
}
48+
49+
/**
50+
* @see HttpResponseHandler#handle(SdkHttpFullResponse, ExecutionAttributes)
51+
*/
52+
@Override
53+
public T handle(SdkHttpFullResponse response, ExecutionAttributes executionAttributes) throws Exception {
54+
SdkStandardLogger.REQUEST_LOGGER.trace(() -> "Parsing service response XML.");
55+
56+
// TODO metadata
57+
T result = unmarshaller.unmarshall(pojoSupplier.apply(response), response);
58+
SdkStandardLogger.REQUEST_LOGGER.trace(() -> "Done parsing service response.");
59+
return result;
60+
}
61+
62+
@Override
63+
public boolean needsConnectionLeftOpen() {
64+
// TODO
65+
return false;
66+
}
67+
68+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2010-2018 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.awscore.protocol.query;
17+
18+
import java.util.function.Supplier;
19+
import software.amazon.awssdk.annotations.SdkProtectedApi;
20+
import software.amazon.awssdk.awscore.AwsRequest;
21+
import software.amazon.awssdk.awscore.AwsResponse;
22+
import software.amazon.awssdk.awscore.http.response.NewStaxResponseHandler;
23+
import software.amazon.awssdk.core.Request;
24+
import software.amazon.awssdk.core.http.HttpResponseHandler;
25+
import software.amazon.awssdk.core.internal.protocol.query.marshall.QueryProtocolMarshaller;
26+
import software.amazon.awssdk.core.internal.protocol.query.unmarshall.QueryProtocolUnmarshaller;
27+
import software.amazon.awssdk.core.protocol.OperationInfo;
28+
import software.amazon.awssdk.core.protocol.ProtocolMarshaller;
29+
import software.amazon.awssdk.core.protocol.SdkPojo;
30+
31+
/**
32+
* Protocol factory for the AWS/Query protocol.
33+
*/
34+
@SdkProtectedApi
35+
public final class AwsEc2ProtocolFactory extends AwsQueryProtocolFactory {
36+
37+
@Override
38+
public <T extends AwsRequest> ProtocolMarshaller<Request<T>> createProtocolMarshaller(OperationInfo operationInfo,
39+
T origRequest) {
40+
return QueryProtocolMarshaller.builder(origRequest)
41+
.operationInfo(operationInfo)
42+
.isEc2(true)
43+
.build();
44+
}
45+
46+
public <T extends AwsResponse> HttpResponseHandler<T> createResponseHandler(Supplier<SdkPojo> pojoSupplier) {
47+
return new NewStaxResponseHandler<>(new QueryProtocolUnmarshaller<>(false), r -> pojoSupplier.get());
48+
}
49+
}

core/aws-core/src/main/java/software/amazon/awssdk/awscore/protocol/query/AwsQueryProtocolFactory.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,32 @@
1515

1616
package software.amazon.awssdk.awscore.protocol.query;
1717

18+
import java.util.function.Supplier;
1819
import software.amazon.awssdk.annotations.SdkProtectedApi;
20+
import software.amazon.awssdk.awscore.AwsResponse;
21+
import software.amazon.awssdk.awscore.http.response.NewStaxResponseHandler;
1922
import software.amazon.awssdk.core.Request;
20-
import software.amazon.awssdk.core.internal.protocol.query.QueryProtocolMarshaller;
23+
import software.amazon.awssdk.core.http.HttpResponseHandler;
24+
import software.amazon.awssdk.core.internal.protocol.query.marshall.QueryProtocolMarshaller;
25+
import software.amazon.awssdk.core.internal.protocol.query.unmarshall.QueryProtocolUnmarshaller;
2126
import software.amazon.awssdk.core.protocol.OperationInfo;
2227
import software.amazon.awssdk.core.protocol.ProtocolMarshaller;
28+
import software.amazon.awssdk.core.protocol.SdkPojo;
2329

2430
/**
2531
* Protocol factory for the AWS/Query protocol.
2632
*/
2733
@SdkProtectedApi
28-
public final class AwsQueryProtocolFactory {
34+
public class AwsQueryProtocolFactory {
2935

3036
public <T extends software.amazon.awssdk.awscore.AwsRequest> ProtocolMarshaller<Request<T>> createProtocolMarshaller(
3137
OperationInfo operationInfo, T origRequest) {
32-
return new QueryProtocolMarshaller<>(operationInfo, origRequest);
38+
return QueryProtocolMarshaller.builder(origRequest)
39+
.operationInfo(operationInfo)
40+
.build();
41+
}
42+
43+
public <T extends AwsResponse> HttpResponseHandler<T> createResponseHandler(Supplier<SdkPojo> pojoSupplier) {
44+
return new NewStaxResponseHandler<>(new QueryProtocolUnmarshaller<>(true), r -> pojoSupplier.get());
3345
}
3446
}

0 commit comments

Comments
 (0)