Skip to content

Commit

Permalink
Added a method to streaming output operations that will load the resp…
Browse files Browse the repository at this point in the history
…onse into memory and provide access to it as a byte buffer or string.
  • Loading branch information
millems committed Dec 13, 2017
1 parent a5e97c5 commit 69c518c
Show file tree
Hide file tree
Showing 9 changed files with 384 additions and 24 deletions.
5 changes: 5 additions & 0 deletions .changes/next-release/feature-AWSSDKforJavav2-d08c3c0.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"category": "AWS SDK for Java v2",
"type": "feature",
"description": "Automatically retry streaming downloads to a file if they fail or are interrupted. [#324](https://github.com/aws/aws-sdk-java-v2/pull/324)"
}
5 changes: 5 additions & 0 deletions .changes/next-release/feature-AWSSDKforJavav2-d976f8d.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"category": "AWS SDK for Java v2",
"type": "feature",
"description": "Added `Bytes` methods to all streaming operations. These methods will load the service response into memory and return a `ResponseBytes` object that eases conversion into other types, like strings. eg. `String object = s3.getObjectBytes(request).asUtf8String()`. [#324](https://github.com/aws/aws-sdk-java-v2/pull/324)"
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

package software.amazon.awssdk.codegen.docs;

import software.amazon.awssdk.core.sync.ResponseBytes;

/**
* Enum describing all the convenience overloads we generate for operation methods.
*/
Expand Down Expand Up @@ -57,5 +59,11 @@ public enum SimpleMethodOverload {
* and returns an unmanaged {@link software.amazon.awssdk.core.sync.ResponseInputStream} to read the response
* contents.
*/
INPUT_STREAM
INPUT_STREAM,

/**
* Simple method only for sync operations that have a streaming output. Takes a request object and return a
* {@link ResponseBytes} to give byte-buffer access and convenience methods for type conversion.
*/
BYTES
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
import software.amazon.awssdk.codegen.utils.PaginatorUtils;
import software.amazon.awssdk.core.sync.ResponseBytes;
import software.amazon.awssdk.core.sync.StreamingResponseHandler;

/**
Expand Down Expand Up @@ -96,6 +97,7 @@ static Map<SimpleMethodOverload, Factory> syncFactories() {
.put(SimpleMethodOverload.NO_ARG, SyncNoArg::new)
.put(SimpleMethodOverload.FILE, SyncFile::new)
.put(SimpleMethodOverload.INPUT_STREAM, SyncInputStream::new)
.put(SimpleMethodOverload.BYTES, SyncBytes::new)
.put(SimpleMethodOverload.PAGINATED, SyncPaginated::new)
.put(SimpleMethodOverload.NO_ARG_PAGINATED, SyncPaginatedNoArg::new)
.build();
Expand Down Expand Up @@ -158,6 +160,33 @@ protected void applyParams(DocumentationBuilder docBuilder) {
}
}

/**
* Provider for streaming output simple methods that return an {@link ResponseBytes} containing the in-memory response content
* and the unmarshalled POJO. Only applicable to operations that have a streaming member in the output shape.
*/
private static class SyncBytes extends SyncOperationDocProvider {

private SyncBytes(IntermediateModel model, OperationModel opModel) {
super(model, opModel);
}

@Override
protected void applyReturns(DocumentationBuilder docBuilder) {
docBuilder.returns(
"A {@link ResponseBytes} that loads the data streamed from the service into memory and exposes it in " +
"convenient in-memory representations like a byte buffer or string. The unmarshalled response object can " +
"be obtained via {@link ResponseBytes#response()}. " + getStreamingOutputDocs());
// Link to non-simple method for discoverability
docBuilder.see("#getObject(%s, StreamingResponseHandler)", opModel.getMethodName(),
opModel.getInput().getVariableType());
}

@Override
protected void applyParams(DocumentationBuilder docBuilder) {
emitRequestParm(docBuilder);
}
}

/**
* Provider for simple method that takes no arguments and creates an empty request object.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import software.amazon.awssdk.core.regions.ServiceMetadata;
import software.amazon.awssdk.core.regions.providers.DefaultAwsRegionProviderChain;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.core.sync.ResponseBytes;
import software.amazon.awssdk.core.sync.ResponseInputStream;
import software.amazon.awssdk.core.sync.StreamingResponseHandler;
import software.amazon.awssdk.utils.SdkAutoCloseable;
Expand Down Expand Up @@ -291,6 +292,7 @@ private List<MethodSpec> streamingSimpleMethods(OperationModel opModel) {
if (opModel.hasStreamingOutput()) {
simpleMethods.add(downloadToFileSimpleMethod(opModel, responseType, requestType));
simpleMethods.add(inputStreamSimpleMethod(opModel, responseType, requestType));
simpleMethods.add(bytesSimpleMethod(opModel, responseType, requestType));
}
return simpleMethods;
}
Expand All @@ -317,8 +319,7 @@ private MethodSpec uploadFromFileSimpleMethod(OperationModel opModel, TypeName r
* @return Simple method for streaming output operations to get content as an input stream.
*/
private MethodSpec inputStreamSimpleMethod(OperationModel opModel, TypeName responseType, ClassName requestType) {
ParameterizedTypeName returnType = ParameterizedTypeName.get(ClassName.get(ResponseInputStream.class),
responseType);
TypeName returnType = ParameterizedTypeName.get(ClassName.get(ResponseInputStream.class), responseType);
return MethodSpec.methodBuilder(opModel.getMethodName())
.returns(returnType)
.addModifiers(Modifier.PUBLIC, Modifier.DEFAULT)
Expand All @@ -331,6 +332,23 @@ private MethodSpec inputStreamSimpleMethod(OperationModel opModel, TypeName resp
.build();
}

/**
* @return Simple method for streaming output operations to get the content as a byte buffer or other in-memory types.
*/
private MethodSpec bytesSimpleMethod(OperationModel opModel, TypeName responseType, ClassName requestType) {
TypeName returnType = ParameterizedTypeName.get(ClassName.get(ResponseBytes.class), responseType);
return MethodSpec.methodBuilder(opModel.getMethodName() + "Bytes")
.returns(returnType)
.addModifiers(Modifier.PUBLIC, Modifier.DEFAULT)
.addParameter(requestType, opModel.getInput().getVariableName())
.addJavadoc(opModel.getDocs(model, ClientType.SYNC, SimpleMethodOverload.BYTES))
.addExceptions(getExceptionClasses(model, opModel))
.addStatement("return $L($L, $T.toBytes())", opModel.getMethodName(),
opModel.getInput().getVariableName(),
ClassName.get(StreamingResponseHandler.class))
.build();
}

/**
* @return Simple method for streaming output operations to write response content to a file.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import software.amazon.awssdk.core.exception.SdkServiceException;
import software.amazon.awssdk.core.regions.ServiceMetadata;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.core.sync.ResponseBytes;
import software.amazon.awssdk.core.sync.ResponseInputStream;
import software.amazon.awssdk.core.sync.StreamingResponseHandler;
import software.amazon.awssdk.services.json.model.APostOperationRequest;
Expand Down Expand Up @@ -75,7 +76,7 @@ static JsonClientBuilder builder() {
* API Documentation</a>
*/
default APostOperationResponse aPostOperation(APostOperationRequest aPostOperationRequest) throws InvalidInputException,
SdkServiceException, SdkClientException, JsonException {
SdkServiceException, SdkClientException, JsonException {
throw new UnsupportedOperationException();
}

Expand Down Expand Up @@ -126,7 +127,7 @@ default APostOperationResponse aPostOperation(Consumer<APostOperationRequest.Bui
*/
default APostOperationWithOutputResponse aPostOperationWithOutput(
APostOperationWithOutputRequest aPostOperationWithOutputRequest) throws InvalidInputException, SdkServiceException,
SdkClientException, JsonException {
SdkClientException, JsonException {
throw new UnsupportedOperationException();
}

Expand All @@ -152,7 +153,7 @@ default APostOperationWithOutputResponse aPostOperationWithOutput(
*/
default APostOperationWithOutputResponse aPostOperationWithOutput(
Consumer<APostOperationWithOutputRequest.Builder> aPostOperationWithOutputRequest) throws InvalidInputException,
SdkServiceException, SdkClientException, JsonException {
SdkServiceException, SdkClientException, JsonException {
return aPostOperationWithOutput(APostOperationWithOutputRequest.builder().apply(aPostOperationWithOutputRequest).build());
}

Expand All @@ -177,7 +178,7 @@ default APostOperationWithOutputResponse aPostOperationWithOutput(
* target="_top">AWS API Documentation</a>
*/
default GetWithoutRequiredMembersResponse getWithoutRequiredMembers() throws InvalidInputException, SdkServiceException,
SdkClientException, JsonException {
SdkClientException, JsonException {
return getWithoutRequiredMembers(GetWithoutRequiredMembersRequest.builder().build());
}

Expand All @@ -203,7 +204,7 @@ default GetWithoutRequiredMembersResponse getWithoutRequiredMembers() throws Inv
*/
default GetWithoutRequiredMembersResponse getWithoutRequiredMembers(
GetWithoutRequiredMembersRequest getWithoutRequiredMembersRequest) throws InvalidInputException, SdkServiceException,
SdkClientException, JsonException {
SdkClientException, JsonException {
throw new UnsupportedOperationException();
}

Expand All @@ -229,9 +230,9 @@ default GetWithoutRequiredMembersResponse getWithoutRequiredMembers(
*/
default GetWithoutRequiredMembersResponse getWithoutRequiredMembers(
Consumer<GetWithoutRequiredMembersRequest.Builder> getWithoutRequiredMembersRequest) throws InvalidInputException,
SdkServiceException, SdkClientException, JsonException {
SdkServiceException, SdkClientException, JsonException {
return getWithoutRequiredMembers(GetWithoutRequiredMembersRequest.builder().apply(getWithoutRequiredMembersRequest)
.build());
.build());
}

/**
Expand All @@ -252,7 +253,7 @@ default GetWithoutRequiredMembersResponse getWithoutRequiredMembers(
*/
default PaginatedOperationWithResultKeyResponse paginatedOperationWithResultKey(
PaginatedOperationWithResultKeyRequest paginatedOperationWithResultKeyRequest) throws SdkServiceException,
SdkClientException, JsonException {
SdkClientException, JsonException {
throw new UnsupportedOperationException();
}

Expand All @@ -276,7 +277,7 @@ default PaginatedOperationWithResultKeyResponse paginatedOperationWithResultKey(
Consumer<PaginatedOperationWithResultKeyRequest.Builder> paginatedOperationWithResultKeyRequest)
throws SdkServiceException, SdkClientException, JsonException {
return paginatedOperationWithResultKey(PaginatedOperationWithResultKeyRequest.builder()
.apply(paginatedOperationWithResultKeyRequest).build());
.apply(paginatedOperationWithResultKeyRequest).build());
}

/**
Expand Down Expand Up @@ -348,7 +349,7 @@ default PaginatedOperationWithResultKeyResponse paginatedOperationWithResultKey(
*/
default PaginatedOperationWithResultKeyPaginator paginatedOperationWithResultKeyIterable(
PaginatedOperationWithResultKeyRequest paginatedOperationWithResultKeyRequest) throws SdkServiceException,
SdkClientException, JsonException {
SdkClientException, JsonException {
throw new UnsupportedOperationException();
}

Expand All @@ -370,7 +371,7 @@ default PaginatedOperationWithResultKeyPaginator paginatedOperationWithResultKey
*/
default PaginatedOperationWithoutResultKeyResponse paginatedOperationWithoutResultKey(
PaginatedOperationWithoutResultKeyRequest paginatedOperationWithoutResultKeyRequest) throws SdkServiceException,
SdkClientException, JsonException {
SdkClientException, JsonException {
throw new UnsupportedOperationException();
}

Expand All @@ -394,7 +395,7 @@ default PaginatedOperationWithoutResultKeyResponse paginatedOperationWithoutResu
Consumer<PaginatedOperationWithoutResultKeyRequest.Builder> paginatedOperationWithoutResultKeyRequest)
throws SdkServiceException, SdkClientException, JsonException {
return paginatedOperationWithoutResultKey(PaginatedOperationWithoutResultKeyRequest.builder()
.apply(paginatedOperationWithoutResultKeyRequest).build());
.apply(paginatedOperationWithoutResultKeyRequest).build());
}

/**
Expand Down Expand Up @@ -466,7 +467,7 @@ default PaginatedOperationWithoutResultKeyResponse paginatedOperationWithoutResu
*/
default PaginatedOperationWithoutResultKeyPaginator paginatedOperationWithoutResultKeyIterable(
PaginatedOperationWithoutResultKeyRequest paginatedOperationWithoutResultKeyRequest) throws SdkServiceException,
SdkClientException, JsonException {
SdkClientException, JsonException {
throw new UnsupportedOperationException();
}

Expand Down Expand Up @@ -499,7 +500,7 @@ default PaginatedOperationWithoutResultKeyPaginator paginatedOperationWithoutRes
*/
default StreamingInputOperationResponse streamingInputOperation(
StreamingInputOperationRequest streamingInputOperationRequest, RequestBody requestBody) throws SdkServiceException,
SdkClientException, JsonException {
SdkClientException, JsonException {
throw new UnsupportedOperationException();
}

Expand Down Expand Up @@ -527,7 +528,7 @@ default StreamingInputOperationResponse streamingInputOperation(
*/
default StreamingInputOperationResponse streamingInputOperation(
StreamingInputOperationRequest streamingInputOperationRequest, Path filePath) throws SdkServiceException,
SdkClientException, JsonException {
SdkClientException, JsonException {
return streamingInputOperation(streamingInputOperationRequest, RequestBody.of(filePath));
}

Expand Down Expand Up @@ -555,7 +556,7 @@ default StreamingInputOperationResponse streamingInputOperation(
* target="_top">AWS API Documentation</a>
*/
default <ReturnT> ReturnT streamingOutputOperation(StreamingOutputOperationRequest streamingOutputOperationRequest,
StreamingResponseHandler<StreamingOutputOperationResponse, ReturnT> streamingResponseHandler)
StreamingResponseHandler<StreamingOutputOperationResponse, ReturnT> streamingResponseHandler)
throws SdkServiceException, SdkClientException, JsonException {
throw new UnsupportedOperationException();
}
Expand Down Expand Up @@ -583,7 +584,7 @@ default <ReturnT> ReturnT streamingOutputOperation(StreamingOutputOperationReque
*/
default StreamingOutputOperationResponse streamingOutputOperation(
StreamingOutputOperationRequest streamingOutputOperationRequest, Path filePath) throws SdkServiceException,
SdkClientException, JsonException {
SdkClientException, JsonException {
return streamingOutputOperation(streamingOutputOperationRequest, StreamingResponseHandler.toFile(filePath));
}

Expand Down Expand Up @@ -611,10 +612,36 @@ default StreamingOutputOperationResponse streamingOutputOperation(
*/
default ResponseInputStream<StreamingOutputOperationResponse> streamingOutputOperation(
StreamingOutputOperationRequest streamingOutputOperationRequest) throws SdkServiceException, SdkClientException,
JsonException {
JsonException {
return streamingOutputOperation(streamingOutputOperationRequest, StreamingResponseHandler.toInputStream());
}

/**
* Some operation with a streaming output
*
* @param streamingOutputOperationRequest
* @return A {@link ResponseBytes} that loads the data streamed from the service into memory and exposes it in
* convenient in-memory representations like a byte buffer or string. The unmarshalled response object can
* be obtained via {@link ResponseBytes#response()}. The service documentation for the response content is
* as follows 'This be a stream'.
* @throws SdkException
* Base class for all exceptions that can be thrown by the SDK (both service and client). Can be used for
* catch all scenarios.
* @throws SdkClientException
* If any client side error occurs such as an IO related failure, failure to get credentials, etc.
* @throws JsonException
* Base class for all service exceptions. Unknown exceptions will be thrown as an instance of this type.
* @sample JsonClient.StreamingOutputOperation
* @see #getObject(streamingOutputOperation, StreamingResponseHandler)
* @see <a href="http://docs.aws.amazon.com/goto/WebAPI/json-service-2010-05-08/StreamingOutputOperation"
* target="_top">AWS API Documentation</a>
*/
default ResponseBytes<StreamingOutputOperationResponse> streamingOutputOperationBytes(
StreamingOutputOperationRequest streamingOutputOperationRequest) throws SdkServiceException, SdkClientException,
JsonException {
return streamingOutputOperation(streamingOutputOperationRequest, StreamingResponseHandler.toBytes());
}

static ServiceMetadata serviceMetadata() {
return ServiceMetadata.of("json-service");
}
Expand Down
Loading

0 comments on commit 69c518c

Please sign in to comment.