
software.amazon.awssdk.services.dynamodb.streams.DefaultDynamoDbStreamsAsyncClient Maven / Gradle / Ivy
/*
* Copyright 2013-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/
package software.amazon.awssdk.services.dynamodb.streams;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.annotations.Generated;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
import software.amazon.awssdk.awscore.client.handler.AwsAsyncClientHandler;
import software.amazon.awssdk.awscore.exception.AwsServiceException;
import software.amazon.awssdk.awscore.internal.protocol.json.AwsJsonProtocol;
import software.amazon.awssdk.awscore.protocol.json.AwsJsonProtocolFactory;
import software.amazon.awssdk.awscore.protocol.json.AwsJsonProtocolMetadata;
import software.amazon.awssdk.core.ApiName;
import software.amazon.awssdk.core.client.handler.AsyncClientHandler;
import software.amazon.awssdk.core.client.handler.ClientExecutionParams;
import software.amazon.awssdk.core.http.HttpResponseHandler;
import software.amazon.awssdk.core.internal.client.config.SdkClientConfiguration;
import software.amazon.awssdk.core.protocol.json.JsonClientMetadata;
import software.amazon.awssdk.core.protocol.json.JsonErrorResponseMetadata;
import software.amazon.awssdk.core.protocol.json.JsonErrorShapeMetadata;
import software.amazon.awssdk.core.protocol.json.JsonOperationMetadata;
import software.amazon.awssdk.core.util.VersionInfo;
import software.amazon.awssdk.services.dynamodb.model.DescribeStreamRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeStreamResponse;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbStreamsRequest;
import software.amazon.awssdk.services.dynamodb.model.ExpiredIteratorException;
import software.amazon.awssdk.services.dynamodb.model.GetRecordsRequest;
import software.amazon.awssdk.services.dynamodb.model.GetRecordsResponse;
import software.amazon.awssdk.services.dynamodb.model.GetShardIteratorRequest;
import software.amazon.awssdk.services.dynamodb.model.GetShardIteratorResponse;
import software.amazon.awssdk.services.dynamodb.model.InternalServerErrorException;
import software.amazon.awssdk.services.dynamodb.model.LimitExceededException;
import software.amazon.awssdk.services.dynamodb.model.ListStreamsRequest;
import software.amazon.awssdk.services.dynamodb.model.ListStreamsResponse;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
import software.amazon.awssdk.services.dynamodb.model.TrimmedDataAccessException;
import software.amazon.awssdk.services.dynamodb.streams.paginators.DescribeStreamPublisher;
import software.amazon.awssdk.services.dynamodb.streams.paginators.ListStreamsPublisher;
import software.amazon.awssdk.services.dynamodb.streams.transform.DescribeStreamRequestMarshaller;
import software.amazon.awssdk.services.dynamodb.streams.transform.GetRecordsRequestMarshaller;
import software.amazon.awssdk.services.dynamodb.streams.transform.GetShardIteratorRequestMarshaller;
import software.amazon.awssdk.services.dynamodb.streams.transform.ListStreamsRequestMarshaller;
import software.amazon.awssdk.services.dynamodb.transform.DescribeStreamResponseUnmarshaller;
import software.amazon.awssdk.services.dynamodb.transform.GetRecordsResponseUnmarshaller;
import software.amazon.awssdk.services.dynamodb.transform.GetShardIteratorResponseUnmarshaller;
import software.amazon.awssdk.services.dynamodb.transform.ListStreamsResponseUnmarshaller;
import software.amazon.awssdk.utils.CompletableFutureUtils;
/**
* Internal implementation of {@link DynamoDbStreamsAsyncClient}.
*
* @see DynamoDbStreamsAsyncClient#builder()
*/
@Generated("software.amazon.awssdk:codegen")
@SdkInternalApi
final class DefaultDynamoDbStreamsAsyncClient implements DynamoDbStreamsAsyncClient {
private static final Logger log = LoggerFactory.getLogger(DefaultDynamoDbStreamsAsyncClient.class);
private final AsyncClientHandler clientHandler;
private final AwsJsonProtocolFactory protocolFactory;
protected DefaultDynamoDbStreamsAsyncClient(SdkClientConfiguration clientConfiguration) {
this.clientHandler = new AwsAsyncClientHandler(clientConfiguration);
this.protocolFactory = init(false);
}
@Override
public final String serviceName() {
return SERVICE_NAME;
}
/**
*
* Returns information about a stream, including the current status of the stream, its Amazon Resource Name (ARN),
* the composition of its shards, and its corresponding DynamoDB table.
*
*
*
* You can call DescribeStream
at a maximum rate of 10 times per second.
*
*
*
* Each shard in the stream has a SequenceNumberRange
associated with it. If the
* SequenceNumberRange
has a StartingSequenceNumber
but no
* EndingSequenceNumber
, then the shard is still open (able to receive more stream records). If both
* StartingSequenceNumber
and EndingSequenceNumber
are present, then that shard is closed
* and can no longer receive more data.
*
*
* @param describeStreamRequest
* Represents the input of a DescribeStream
operation.
* @return A Java Future containing the result of the DescribeStream operation returned by the service.
* The CompletableFuture returned by this method can be completed exceptionally with the following
* exceptions.
*
* - ResourceNotFoundException The operation tried to access a nonexistent stream.
* - InternalServerErrorException An error occurred on the server side.
* - SdkException Base class for all exceptions that can be thrown by the SDK (both service and client).
* Can be used for catch all scenarios.
* - SdkClientException If any client side error occurs such as an IO related failure, failure to get
* credentials, etc.
* - DynamoDbStreamsException Base class for all service exceptions. Unknown exceptions will be thrown as
* an instance of this type.
*
* @sample DynamoDbStreamsAsyncClient.DescribeStream
* @see AWS API Documentation
*/
@Override
public CompletableFuture describeStream(DescribeStreamRequest describeStreamRequest) {
try {
HttpResponseHandler responseHandler = protocolFactory.createResponseHandler(
new JsonOperationMetadata().withPayloadJson(true).withHasStreamingSuccessResponse(false),
new DescribeStreamResponseUnmarshaller());
HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory);
return clientHandler.execute(new ClientExecutionParams()
.withMarshaller(new DescribeStreamRequestMarshaller(protocolFactory)).withResponseHandler(responseHandler)
.withErrorResponseHandler(errorResponseHandler).withInput(describeStreamRequest));
} catch (Throwable t) {
return CompletableFutureUtils.failedFuture(t);
}
}
/**
*
* Returns information about a stream, including the current status of the stream, its Amazon Resource Name (ARN),
* the composition of its shards, and its corresponding DynamoDB table.
*
*
*
* You can call DescribeStream
at a maximum rate of 10 times per second.
*
*
*
* Each shard in the stream has a SequenceNumberRange
associated with it. If the
* SequenceNumberRange
has a StartingSequenceNumber
but no
* EndingSequenceNumber
, then the shard is still open (able to receive more stream records). If both
* StartingSequenceNumber
and EndingSequenceNumber
are present, then that shard is closed
* and can no longer receive more data.
*
*
*
* This is a variant of
* {@link #describeStream(software.amazon.awssdk.services.dynamodb.model.DescribeStreamRequest)} operation. The
* return type is a custom publisher that can be subscribed to request a stream of response pages. SDK will
* internally handle making service calls for you.
*
*
* When the operation is called, an instance of this class is returned. At this point, no service calls are made yet
* and so there is no guarantee that the request is valid. If there are errors in your request, you will see the
* failures only after you start streaming the data. The subscribe method should be called as a request to start
* streaming data. For more info, see
* {@link org.reactivestreams.Publisher#subscribe(org.reactivestreams.Subscriber)}. Each call to the subscribe
* method will result in a new {@link org.reactivestreams.Subscription} i.e., a new contract to stream data from the
* starting request.
*
*
*
* The following are few ways to use the response class:
*
* 1) Using the forEach helper method
*
*
* {@code
* software.amazon.awssdk.services.dynamodb.streams.paginators.DescribeStreamPublisher publisher = client.describeStreamPaginator(request);
* CompletableFuture future = publisher.forEach(res -> { // Do something with the response });
* future.get();
* }
*
*
* 2) Using a custom subscriber
*
*
* {@code
* software.amazon.awssdk.services.dynamodb.streams.paginators.DescribeStreamPublisher publisher = client.describeStreamPaginator(request);
* publisher.subscribe(new Subscriber() {
*
* public void onSubscribe(org.reactivestreams.Subscriber subscription) { //... };
*
*
* public void onNext(software.amazon.awssdk.services.dynamodb.model.DescribeStreamResponse response) { //... };
* });}
*
*
* As the response is a publisher, it can work well with third party reactive streams implementations like RxJava2.
*
* Note: If you prefer to have control on service calls, use the
* {@link #describeStream(software.amazon.awssdk.services.dynamodb.model.DescribeStreamRequest)} operation.
*
*
* @param describeStreamRequest
* Represents the input of a DescribeStream
operation.
* @return A custom publisher that can be subscribed to request a stream of response pages.
* The CompletableFuture returned by this method can be completed exceptionally with the following
* exceptions.
*
* - ResourceNotFoundException The operation tried to access a nonexistent stream.
* - InternalServerErrorException An error occurred on the server side.
* - SdkException Base class for all exceptions that can be thrown by the SDK (both service and client).
* Can be used for catch all scenarios.
* - SdkClientException If any client side error occurs such as an IO related failure, failure to get
* credentials, etc.
* - DynamoDbStreamsException Base class for all service exceptions. Unknown exceptions will be thrown as
* an instance of this type.
*
* @sample DynamoDbStreamsAsyncClient.DescribeStream
* @see AWS API Documentation
*/
public DescribeStreamPublisher describeStreamPaginator(DescribeStreamRequest describeStreamRequest) {
return new DescribeStreamPublisher(this, applyPaginatorUserAgent(describeStreamRequest));
}
/**
*
* Retrieves the stream records from a given shard.
*
*
* Specify a shard iterator using the ShardIterator
parameter. The shard iterator specifies the
* position in the shard from which you want to start reading stream records sequentially. If there are no stream
* records available in the portion of the shard that the iterator points to, GetRecords
returns an
* empty list. Note that it might take multiple calls to get to a portion of the shard that contains stream records.
*
*
*
* GetRecords
can retrieve a maximum of 1 MB of data or 1000 stream records, whichever comes first.
*
*
*
* @param getRecordsRequest
* Represents the input of a GetRecords
operation.
* @return A Java Future containing the result of the GetRecords operation returned by the service.
* The CompletableFuture returned by this method can be completed exceptionally with the following
* exceptions.
*
* - ResourceNotFoundException The operation tried to access a nonexistent stream.
* - LimitExceededException Your request rate is too high. The AWS SDKs for DynamoDB automatically retry
* requests that receive this exception. Your request is eventually successful, unless your retry queue is
* too large to finish. Reduce the frequency of requests and use exponential backoff. For more information,
* go to Error Retries and Exponential Backoff in the Amazon DynamoDB Developer Guide.
* - InternalServerErrorException An error occurred on the server side.
* - ExpiredIteratorException The shard iterator has expired and can no longer be used to retrieve stream
* records. A shard iterator expires 15 minutes after it is retrieved using the
*
GetShardIterator
action.
* - TrimmedDataAccessException The operation attempted to read past the oldest stream record in a
* shard.
*
* In DynamoDB Streams, there is a 24 hour limit on data retention. Stream records whose age exceeds this
* limit are subject to removal (trimming) from the stream. You might receive a TrimmedDataAccessException
* if:
*
*
* -
*
* You request a shard iterator with a sequence number older than the trim point (24 hours).
*
*
* -
*
* You obtain a shard iterator, but before you use the iterator in a GetRecords
request, a
* stream record in the shard exceeds the 24 hour period and is trimmed. This causes the iterator to access
* a record that no longer exists.
*
*
* - SdkException Base class for all exceptions that can be thrown by the SDK (both service and client).
* Can be used for catch all scenarios.
* - SdkClientException If any client side error occurs such as an IO related failure, failure to get
* credentials, etc.
* - DynamoDbStreamsException Base class for all service exceptions. Unknown exceptions will be thrown as
* an instance of this type.
*
* @sample DynamoDbStreamsAsyncClient.GetRecords
* @see AWS
* API Documentation
*/
@Override
public CompletableFuture getRecords(GetRecordsRequest getRecordsRequest) {
try {
HttpResponseHandler responseHandler = protocolFactory.createResponseHandler(
new JsonOperationMetadata().withPayloadJson(true).withHasStreamingSuccessResponse(false),
new GetRecordsResponseUnmarshaller());
HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory);
return clientHandler.execute(new ClientExecutionParams()
.withMarshaller(new GetRecordsRequestMarshaller(protocolFactory)).withResponseHandler(responseHandler)
.withErrorResponseHandler(errorResponseHandler).withInput(getRecordsRequest));
} catch (Throwable t) {
return CompletableFutureUtils.failedFuture(t);
}
}
/**
*
* Returns a shard iterator. A shard iterator provides information about how to retrieve the stream records from
* within a shard. Use the shard iterator in a subsequent GetRecords
request to read the stream records
* from the shard.
*
*
*
* A shard iterator expires 15 minutes after it is returned to the requester.
*
*
*
* @param getShardIteratorRequest
* Represents the input of a GetShardIterator
operation.
* @return A Java Future containing the result of the GetShardIterator operation returned by the service.
* The CompletableFuture returned by this method can be completed exceptionally with the following
* exceptions.
*
* - ResourceNotFoundException The operation tried to access a nonexistent stream.
* - InternalServerErrorException An error occurred on the server side.
* - TrimmedDataAccessException The operation attempted to read past the oldest stream record in a
* shard.
*
* In DynamoDB Streams, there is a 24 hour limit on data retention. Stream records whose age exceeds this
* limit are subject to removal (trimming) from the stream. You might receive a TrimmedDataAccessException
* if:
*
*
* -
*
* You request a shard iterator with a sequence number older than the trim point (24 hours).
*
*
* -
*
* You obtain a shard iterator, but before you use the iterator in a GetRecords
request, a
* stream record in the shard exceeds the 24 hour period and is trimmed. This causes the iterator to access
* a record that no longer exists.
*
*
* - SdkException Base class for all exceptions that can be thrown by the SDK (both service and client).
* Can be used for catch all scenarios.
* - SdkClientException If any client side error occurs such as an IO related failure, failure to get
* credentials, etc.
* - DynamoDbStreamsException Base class for all service exceptions. Unknown exceptions will be thrown as
* an instance of this type.
*
* @sample DynamoDbStreamsAsyncClient.GetShardIterator
* @see AWS API Documentation
*/
@Override
public CompletableFuture getShardIterator(GetShardIteratorRequest getShardIteratorRequest) {
try {
HttpResponseHandler responseHandler = protocolFactory.createResponseHandler(
new JsonOperationMetadata().withPayloadJson(true).withHasStreamingSuccessResponse(false),
new GetShardIteratorResponseUnmarshaller());
HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory);
return clientHandler.execute(new ClientExecutionParams()
.withMarshaller(new GetShardIteratorRequestMarshaller(protocolFactory)).withResponseHandler(responseHandler)
.withErrorResponseHandler(errorResponseHandler).withInput(getShardIteratorRequest));
} catch (Throwable t) {
return CompletableFutureUtils.failedFuture(t);
}
}
/**
*
* Returns an array of stream ARNs associated with the current account and endpoint. If the TableName
* parameter is present, then ListStreams
will return only the streams ARNs for that table.
*
*
*
* You can call ListStreams
at a maximum rate of 5 times per second.
*
*
*
* @param listStreamsRequest
* Represents the input of a ListStreams
operation.
* @return A Java Future containing the result of the ListStreams operation returned by the service.
* The CompletableFuture returned by this method can be completed exceptionally with the following
* exceptions.
*
* - ResourceNotFoundException The operation tried to access a nonexistent stream.
* - InternalServerErrorException An error occurred on the server side.
* - SdkException Base class for all exceptions that can be thrown by the SDK (both service and client).
* Can be used for catch all scenarios.
* - SdkClientException If any client side error occurs such as an IO related failure, failure to get
* credentials, etc.
* - DynamoDbStreamsException Base class for all service exceptions. Unknown exceptions will be thrown as
* an instance of this type.
*
* @sample DynamoDbStreamsAsyncClient.ListStreams
* @see AWS
* API Documentation
*/
@Override
public CompletableFuture listStreams(ListStreamsRequest listStreamsRequest) {
try {
HttpResponseHandler responseHandler = protocolFactory.createResponseHandler(
new JsonOperationMetadata().withPayloadJson(true).withHasStreamingSuccessResponse(false),
new ListStreamsResponseUnmarshaller());
HttpResponseHandler errorResponseHandler = createErrorResponseHandler(protocolFactory);
return clientHandler.execute(new ClientExecutionParams()
.withMarshaller(new ListStreamsRequestMarshaller(protocolFactory)).withResponseHandler(responseHandler)
.withErrorResponseHandler(errorResponseHandler).withInput(listStreamsRequest));
} catch (Throwable t) {
return CompletableFutureUtils.failedFuture(t);
}
}
/**
*
* Returns an array of stream ARNs associated with the current account and endpoint. If the TableName
* parameter is present, then ListStreams
will return only the streams ARNs for that table.
*
*
*
* You can call ListStreams
at a maximum rate of 5 times per second.
*
*
*
* This is a variant of {@link #listStreams(software.amazon.awssdk.services.dynamodb.model.ListStreamsRequest)}
* operation. The return type is a custom publisher that can be subscribed to request a stream of response pages.
* SDK will internally handle making service calls for you.
*
*
* When the operation is called, an instance of this class is returned. At this point, no service calls are made yet
* and so there is no guarantee that the request is valid. If there are errors in your request, you will see the
* failures only after you start streaming the data. The subscribe method should be called as a request to start
* streaming data. For more info, see
* {@link org.reactivestreams.Publisher#subscribe(org.reactivestreams.Subscriber)}. Each call to the subscribe
* method will result in a new {@link org.reactivestreams.Subscription} i.e., a new contract to stream data from the
* starting request.
*
*
*
* The following are few ways to use the response class:
*
* 1) Using the forEach helper method
*
*
* {@code
* software.amazon.awssdk.services.dynamodb.streams.paginators.ListStreamsPublisher publisher = client.listStreamsPaginator(request);
* CompletableFuture future = publisher.forEach(res -> { // Do something with the response });
* future.get();
* }
*
*
* 2) Using a custom subscriber
*
*
* {@code
* software.amazon.awssdk.services.dynamodb.streams.paginators.ListStreamsPublisher publisher = client.listStreamsPaginator(request);
* publisher.subscribe(new Subscriber() {
*
* public void onSubscribe(org.reactivestreams.Subscriber subscription) { //... };
*
*
* public void onNext(software.amazon.awssdk.services.dynamodb.model.ListStreamsResponse response) { //... };
* });}
*
*
* As the response is a publisher, it can work well with third party reactive streams implementations like RxJava2.
*
* Note: If you prefer to have control on service calls, use the
* {@link #listStreams(software.amazon.awssdk.services.dynamodb.model.ListStreamsRequest)} operation.
*
*
* @param listStreamsRequest
* Represents the input of a ListStreams
operation.
* @return A custom publisher that can be subscribed to request a stream of response pages.
* The CompletableFuture returned by this method can be completed exceptionally with the following
* exceptions.
*
* - ResourceNotFoundException The operation tried to access a nonexistent stream.
* - InternalServerErrorException An error occurred on the server side.
* - SdkException Base class for all exceptions that can be thrown by the SDK (both service and client).
* Can be used for catch all scenarios.
* - SdkClientException If any client side error occurs such as an IO related failure, failure to get
* credentials, etc.
* - DynamoDbStreamsException Base class for all service exceptions. Unknown exceptions will be thrown as
* an instance of this type.
*
* @sample DynamoDbStreamsAsyncClient.ListStreams
* @see AWS
* API Documentation
*/
public ListStreamsPublisher listStreamsPaginator(ListStreamsRequest listStreamsRequest) {
return new ListStreamsPublisher(this, applyPaginatorUserAgent(listStreamsRequest));
}
@Override
public void close() {
clientHandler.close();
}
private software.amazon.awssdk.awscore.protocol.json.AwsJsonProtocolFactory init(boolean supportsCbor) {
return new AwsJsonProtocolFactory(new JsonClientMetadata()
.withSupportsCbor(supportsCbor)
.withSupportsIon(false)
.withBaseServiceExceptionClass(software.amazon.awssdk.services.dynamodb.model.DynamoDbException.class)
.addErrorMetadata(
new JsonErrorShapeMetadata().withErrorCode("TrimmedDataAccessException").withModeledClass(
TrimmedDataAccessException.class))
.addErrorMetadata(
new JsonErrorShapeMetadata().withErrorCode("ResourceNotFoundException").withModeledClass(
ResourceNotFoundException.class))
.addErrorMetadata(
new JsonErrorShapeMetadata().withErrorCode("ExpiredIteratorException").withModeledClass(
ExpiredIteratorException.class))
.addErrorMetadata(
new JsonErrorShapeMetadata().withErrorCode("InternalServerError").withModeledClass(
InternalServerErrorException.class))
.addErrorMetadata(
new JsonErrorShapeMetadata().withErrorCode("LimitExceededException").withModeledClass(
LimitExceededException.class)), AwsJsonProtocolMetadata.builder().protocolVersion("1.0")
.protocol(AwsJsonProtocol.AWS_JSON).build());
}
private T applyPaginatorUserAgent(T request) {
Consumer userAgentApplier = b -> b.addApiName(ApiName.builder()
.version(VersionInfo.SDK_VERSION).name("PAGINATED").build());
AwsRequestOverrideConfiguration overrideConfiguration = request.overrideConfiguration()
.map(c -> c.toBuilder().applyMutation(userAgentApplier).build())
.orElse((AwsRequestOverrideConfiguration.builder().applyMutation(userAgentApplier).build()));
return (T) request.toBuilder().overrideConfiguration(overrideConfiguration).build();
}
private HttpResponseHandler createErrorResponseHandler(AwsJsonProtocolFactory protocolFactory) {
return protocolFactory.createErrorResponseHandler(new JsonErrorResponseMetadata());
}
}