1
15
16 package software.amazon.awssdk.protocols.xml;
17
18 import static java.util.Collections.unmodifiableList;
19
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.Optional;
23 import java.util.function.Function;
24 import java.util.function.Supplier;
25 import software.amazon.awssdk.annotations.SdkProtectedApi;
26 import software.amazon.awssdk.awscore.AwsResponse;
27 import software.amazon.awssdk.awscore.exception.AwsServiceException;
28 import software.amazon.awssdk.core.Response;
29 import software.amazon.awssdk.core.SdkPojo;
30 import software.amazon.awssdk.core.client.config.SdkClientConfiguration;
31 import software.amazon.awssdk.core.client.config.SdkClientOption;
32 import software.amazon.awssdk.core.http.HttpResponseHandler;
33 import software.amazon.awssdk.core.internal.http.CombinedResponseHandler;
34 import software.amazon.awssdk.http.SdkHttpFullRequest;
35 import software.amazon.awssdk.protocols.core.ExceptionMetadata;
36 import software.amazon.awssdk.protocols.core.OperationInfo;
37 import software.amazon.awssdk.protocols.core.OperationMetadataAttribute;
38 import software.amazon.awssdk.protocols.core.ProtocolMarshaller;
39 import software.amazon.awssdk.protocols.query.unmarshall.AwsXmlErrorProtocolUnmarshaller;
40 import software.amazon.awssdk.protocols.query.unmarshall.XmlElement;
41 import software.amazon.awssdk.protocols.xml.internal.marshall.XmlGenerator;
42 import software.amazon.awssdk.protocols.xml.internal.marshall.XmlProtocolMarshaller;
43 import software.amazon.awssdk.protocols.xml.internal.unmarshall.AwsXmlErrorTransformer;
44 import software.amazon.awssdk.protocols.xml.internal.unmarshall.AwsXmlResponseHandler;
45 import software.amazon.awssdk.protocols.xml.internal.unmarshall.AwsXmlResponseTransformer;
46 import software.amazon.awssdk.protocols.xml.internal.unmarshall.AwsXmlUnmarshallingContext;
47 import software.amazon.awssdk.protocols.xml.internal.unmarshall.XmlProtocolUnmarshaller;
48
49
53 @SdkProtectedApi
54 public class AwsXmlProtocolFactory {
55
56
59 public static final OperationMetadataAttribute<String> XML_NAMESPACE_ATTRIBUTE =
60 new OperationMetadataAttribute<>(String.class);
61
62
68 public static final OperationMetadataAttribute<String> ROOT_MARSHALL_LOCATION_ATTRIBUTE =
69 new OperationMetadataAttribute<>(String.class);
70
71 private static final XmlProtocolUnmarshaller XML_PROTOCOL_UNMARSHALLER = XmlProtocolUnmarshaller.create();
72
73 private final List<ExceptionMetadata> modeledExceptions;
74 private final Supplier<SdkPojo> defaultServiceExceptionSupplier;
75 private final AwsXmlErrorProtocolUnmarshaller errorUnmarshaller;
76 private final SdkClientConfiguration clientConfiguration;
77
78 AwsXmlProtocolFactory(Builder<?> builder) {
79 this.modeledExceptions = unmodifiableList(builder.modeledExceptions);
80 this.defaultServiceExceptionSupplier = builder.defaultServiceExceptionSupplier;
81 this.clientConfiguration = builder.clientConfiguration;
82 this.errorUnmarshaller = AwsXmlErrorProtocolUnmarshaller
83 .builder()
84 .defaultExceptionSupplier(defaultServiceExceptionSupplier)
85 .exceptions(modeledExceptions)
86 .errorUnmarshaller(XML_PROTOCOL_UNMARSHALLER)
87 .errorRootExtractor(this::getErrorRoot)
88 .build();
89 }
90
91
96 public ProtocolMarshaller<SdkHttpFullRequest> createProtocolMarshaller(OperationInfo operationInfo) {
97 return XmlProtocolMarshaller.builder()
98 .endpoint(clientConfiguration.option(SdkClientOption.ENDPOINT))
99 .xmlGenerator(createGenerator(operationInfo))
100 .operationInfo(operationInfo)
101 .build();
102 }
103
104 public <T extends AwsResponse> HttpResponseHandler<T> createResponseHandler(Supplier<SdkPojo> pojoSupplier,
105 XmlOperationMetadata staxOperationMetadata) {
106 return new AwsXmlResponseHandler<>(
107 XML_PROTOCOL_UNMARSHALLER, r -> pojoSupplier.get(),
108 staxOperationMetadata.isHasStreamingSuccessResponse());
109 }
110
111 protected <T extends AwsResponse> Function<AwsXmlUnmarshallingContext, T> createResponseTransformer(
112 Supplier<SdkPojo> pojoSupplier) {
113
114 return new AwsXmlResponseTransformer<>(
115 XML_PROTOCOL_UNMARSHALLER, r -> pojoSupplier.get());
116 }
117
118 protected Function<AwsXmlUnmarshallingContext, AwsServiceException> createErrorTransformer() {
119 return AwsXmlErrorTransformer.builder()
120 .defaultExceptionSupplier(defaultServiceExceptionSupplier)
121 .exceptions(modeledExceptions)
122 .errorUnmarshaller(XML_PROTOCOL_UNMARSHALLER)
123 .build();
124 }
125
126 public HttpResponseHandler<AwsServiceException> createErrorResponseHandler() {
127 return errorUnmarshaller;
128 }
129
130 public <T extends AwsResponse> HttpResponseHandler<Response<T>> createCombinedResponseHandler(
131 Supplier<SdkPojo> pojoSupplier, XmlOperationMetadata staxOperationMetadata) {
132
133 return new CombinedResponseHandler<>(createResponseHandler(pojoSupplier, staxOperationMetadata),
134 createErrorResponseHandler());
135 }
136
137
144 Optional<XmlElement> getErrorRoot(XmlElement document) {
145 return document.getOptionalElementByName("Error");
146 }
147
148 private XmlGenerator createGenerator(OperationInfo operationInfo) {
149 return operationInfo.hasPayloadMembers() ?
150 XmlGenerator.create(operationInfo.addtionalMetadata(XML_NAMESPACE_ATTRIBUTE)) :
151 null;
152 }
153
154 public static Builder builder() {
155 return new Builder();
156 }
157
158
161 public static class Builder<SubclassT extends Builder> {
162
163 private final List<ExceptionMetadata> modeledExceptions = new ArrayList<>();
164 private Supplier<SdkPojo> defaultServiceExceptionSupplier;
165 private SdkClientConfiguration clientConfiguration;
166
167 Builder() {
168 }
169
170
176 public final SubclassT registerModeledException(ExceptionMetadata errorMetadata) {
177 modeledExceptions.add(errorMetadata);
178 return getSubclass();
179 }
180
181
188 public SubclassT defaultServiceExceptionSupplier(Supplier<SdkPojo> exceptionBuilderSupplier) {
189 this.defaultServiceExceptionSupplier = exceptionBuilderSupplier;
190 return getSubclass();
191 }
192
193
199 public SubclassT clientConfiguration(SdkClientConfiguration clientConfiguration) {
200 this.clientConfiguration = clientConfiguration;
201 return getSubclass();
202 }
203
204 @SuppressWarnings("unchecked")
205 private SubclassT getSubclass() {
206 return (SubclassT) this;
207 }
208
209 public AwsXmlProtocolFactory build() {
210 return new AwsXmlProtocolFactory(this);
211 }
212 }
213 }
214