All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.amazonaws.services.sqs.AmazonSQSRequesterClient Maven / Gradle / Ivy

Go to download

An Amazon SQS client that supports creating lightweight, automatically-deleted temporary queues, for use in common messaging patterns such as Request/Response. See http://aws.amazon.com/sqs.

The newest version!
package com.amazonaws.services.sqs;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;

import com.amazonaws.services.sqs.util.Constants;
import com.amazonaws.services.sqs.util.SQSMessageConsumer;
import com.amazonaws.services.sqs.util.SQSQueueUtils;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.CreateQueueRequest;
import software.amazon.awssdk.services.sqs.model.DeleteQueueRequest;
import software.amazon.awssdk.services.sqs.model.Message;
import software.amazon.awssdk.services.sqs.model.MessageAttributeValue;
import software.amazon.awssdk.services.sqs.model.SendMessageRequest;

/**
 * Implementation of the request/response interfaces that creates a single
 * temporary queue for each response message.
 */
class AmazonSQSRequesterClient implements AmazonSQSRequester {
    private final SqsClient sqs;
    private final String queuePrefix;
    private final Map queueAttributes;
    private final Consumer exceptionHandler;
    
    private final Set responseConsumers = Collections.newSetFromMap(new ConcurrentHashMap<>());

    private Runnable shutdownHook;
    
    AmazonSQSRequesterClient(SqsClient sqs, String queuePrefix, Map queueAttributes) {
        this(sqs, queuePrefix, queueAttributes, SQSQueueUtils.DEFAULT_EXCEPTION_HANDLER);
    }

    AmazonSQSRequesterClient(SqsClient sqs, String queuePrefix, Map queueAttributes,
                Consumer exceptionHandler) {
        this.sqs = sqs;
        this.queuePrefix = queuePrefix;
        this.queueAttributes = new HashMap<>(queueAttributes);
        this.exceptionHandler = exceptionHandler;
    }

    public void setShutdownHook(Runnable shutdownHook) {
        this.shutdownHook = shutdownHook;
    }

    @Override
    public SqsClient getAmazonSQS() {
        return sqs;
    }

    @Override
    public Message sendMessageAndGetResponse(SendMessageRequest request, int timeout, TimeUnit unit) {
        return SQSQueueUtils.waitForFuture(sendMessageAndGetResponseAsync(request, timeout, unit));
    }

    @Override
    public CompletableFuture sendMessageAndGetResponseAsync(SendMessageRequest request, int timeout, TimeUnit unit) {
        String queueName = queuePrefix + UUID.randomUUID().toString();
        CreateQueueRequest createQueueRequest = CreateQueueRequest.builder()
                .queueName(queueName)
                .attributesWithStrings(queueAttributes).build();
        String responseQueueUrl = sqs.createQueue(createQueueRequest).queueUrl();

        SendMessageRequest requestWithResponseUrl = SQSQueueUtils.copyWithExtraAttributes(request,
                Collections.singletonMap(Constants.RESPONSE_QUEUE_URL_ATTRIBUTE_NAME,
                        MessageAttributeValue.builder().dataType("String").stringValue(responseQueueUrl).build()));
        // TODO-RS: Should be using sendMessageAsync
        sqs.sendMessage(requestWithResponseUrl);

        CompletableFuture future = new CompletableFuture<>();
        
        // TODO-RS: accept an AmazonSQSAsync instead and use its threads instead of our own.
        // TODO-RS: complete the future exceptionally, for the right set of SQS exceptions
        SQSMessageConsumer consumer = new ResponseListener(responseQueueUrl, future);
        responseConsumers.add(consumer);
        consumer.runFor(timeout, unit);
        return future;
    }

    private class ResponseListener extends SQSMessageConsumer {

        private final CompletableFuture future;
        
        public ResponseListener(String queueUrl, CompletableFuture future) {
            // TODO-RS: Rethink this to avoid subclassing a class that now has a proper builder.
            super(AmazonSQSRequesterClient.this.sqs, queueUrl, message -> {}, null, AmazonSQSRequesterClient.this.exceptionHandler);
            this.future = future;
        }
        
        @Override
        protected void accept(Message message) {
            future.complete(message);
            super.shutdown();
        }
        
        @Override
        protected void runShutdownHook() {
            future.completeExceptionally(new TimeoutException());
            sqs.deleteQueue(DeleteQueueRequest.builder().queueUrl(queueUrl).build());
            responseConsumers.remove(this);
        }
    }
    
    @Override
    public void shutdown() {
        responseConsumers.forEach(SQSMessageConsumer::terminate);
        if (shutdownHook != null) {
            shutdownHook.run();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy