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.protocols.xml; 17 18 import java.util.Optional; 19 import java.util.function.Supplier; 20 import software.amazon.awssdk.annotations.SdkProtectedApi; 21 import software.amazon.awssdk.awscore.AwsResponse; 22 import software.amazon.awssdk.core.Response; 23 import software.amazon.awssdk.core.SdkPojo; 24 import software.amazon.awssdk.core.http.HttpResponseHandler; 25 import software.amazon.awssdk.protocols.core.OperationInfo; 26 import software.amazon.awssdk.protocols.query.unmarshall.XmlElement; 27 import software.amazon.awssdk.protocols.xml.internal.marshall.XmlGenerator; 28 import software.amazon.awssdk.protocols.xml.internal.unmarshall.AwsXmlPredicatedResponseHandler; 29 import software.amazon.awssdk.protocols.xml.internal.unmarshall.DecorateErrorFromResponseBodyUnmarshaller; 30 31 /** 32 * Factory to generate the various protocol handlers and generators to be used for communicating with 33 * Amazon S3. S3 has some unique differences from typical REST/XML that warrant a custom protocol factory. 34 */ 35 @SdkProtectedApi 36 public final class AwsS3ProtocolFactory extends AwsXmlProtocolFactory { AwsS3ProtocolFactory(Builder builder)37 private AwsS3ProtocolFactory(Builder builder) { 38 super(builder); 39 } 40 41 /** 42 * For Amazon S3, the Code, Message, and modeled fields are in the top level document. 43 * 44 * @param document Root XML document. 45 * @return If error root is found than a fulfilled {@link Optional}, otherwise an empty one. 46 */ 47 @Override getErrorRoot(XmlElement document)48 Optional<XmlElement> getErrorRoot(XmlElement document) { 49 return Optional.of(document); 50 } 51 builder()52 public static Builder builder() { 53 return new Builder(); 54 } 55 56 /** 57 * Builder for {@link AwsS3ProtocolFactory}. 58 */ 59 public static final class Builder extends AwsXmlProtocolFactory.Builder<Builder> { 60 Builder()61 private Builder() { 62 } 63 64 @Override build()65 public AwsS3ProtocolFactory build() { 66 return new AwsS3ProtocolFactory(this); 67 } 68 } 69 70 @Override createCombinedResponseHandler( Supplier<SdkPojo> pojoSupplier, XmlOperationMetadata staxOperationMetadata)71 public <T extends AwsResponse> HttpResponseHandler<Response<T>> createCombinedResponseHandler( 72 Supplier<SdkPojo> pojoSupplier, XmlOperationMetadata staxOperationMetadata) { 73 74 return createErrorCouldBeInBodyResponseHandler(pojoSupplier, staxOperationMetadata); 75 } 76 77 /** 78 * Creates a {@link XmlGenerator} with a S3XmlWriter. 79 */ 80 @Override createGenerator(OperationInfo operationInfo)81 protected XmlGenerator createGenerator(OperationInfo operationInfo) { 82 return operationInfo.hasPayloadMembers() ? 83 XmlGenerator.create(operationInfo.addtionalMetadata(XML_NAMESPACE_ATTRIBUTE), true) : 84 null; 85 } 86 createErrorCouldBeInBodyResponseHandler( Supplier<SdkPojo> pojoSupplier, XmlOperationMetadata staxOperationMetadata)87 private <T extends AwsResponse> HttpResponseHandler<Response<T>> createErrorCouldBeInBodyResponseHandler( 88 Supplier<SdkPojo> pojoSupplier, XmlOperationMetadata staxOperationMetadata) { 89 90 return new AwsXmlPredicatedResponseHandler<>(r -> pojoSupplier.get(), 91 createResponseTransformer(pojoSupplier), 92 createErrorTransformer(), 93 DecorateErrorFromResponseBodyUnmarshaller.of(this::getErrorRoot), 94 staxOperationMetadata.isHasStreamingSuccessResponse()); 95 } 96 } 97