org.apache.camel.component.aws2.sqs.Sqs2Producer Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 org.apache.camel.component.aws2.sqs;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.spi.HeaderFilterStrategy;
import org.apache.camel.support.DefaultProducer;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.URISupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.DeleteMessageRequest;
import software.amazon.awssdk.services.sqs.model.DeleteMessageResponse;
import software.amazon.awssdk.services.sqs.model.DeleteQueueRequest;
import software.amazon.awssdk.services.sqs.model.DeleteQueueResponse;
import software.amazon.awssdk.services.sqs.model.ListQueuesRequest;
import software.amazon.awssdk.services.sqs.model.ListQueuesResponse;
import software.amazon.awssdk.services.sqs.model.MessageAttributeValue;
import software.amazon.awssdk.services.sqs.model.PurgeQueueRequest;
import software.amazon.awssdk.services.sqs.model.PurgeQueueResponse;
import software.amazon.awssdk.services.sqs.model.SendMessageBatchRequest;
import software.amazon.awssdk.services.sqs.model.SendMessageBatchRequestEntry;
import software.amazon.awssdk.services.sqs.model.SendMessageBatchResponse;
import software.amazon.awssdk.services.sqs.model.SendMessageRequest;
import software.amazon.awssdk.services.sqs.model.SendMessageResponse;
/**
* A Producer which sends messages to the Amazon Web Service Simple Queue Service
* AWS SQS
*/
public class Sqs2Producer extends DefaultProducer {
private static final Logger LOG = LoggerFactory.getLogger(Sqs2Producer.class);
private static final int MAX_ATTRIBUTES = 10;
private static final String MAX_MESSAGE
= "Number of message headers exceeded. At most " + MAX_ATTRIBUTES + " headers is allowed when sending to AWS SQS.";
private transient String sqsProducerToString;
public Sqs2Producer(Sqs2Endpoint endpoint) {
super(endpoint);
if (endpoint.getConfiguration().isFifoQueue()
&& ObjectHelper.isEmpty(getEndpoint().getConfiguration().getMessageGroupIdStrategy())) {
throw new IllegalArgumentException("messageGroupIdStrategy must be set for FIFO queues.");
}
}
@Override
public void process(Exchange exchange) throws Exception {
Sqs2Operations operation = determineOperation(exchange);
if (ObjectHelper.isEmpty(operation)) {
processSingleMessage(exchange);
} else {
switch (operation) {
case sendBatchMessage:
sendBatchMessage(getClient(), exchange);
break;
case deleteMessage:
deleteMessage(getClient(), exchange);
break;
case listQueues:
listQueues(getClient(), exchange);
break;
case purgeQueue:
purgeQueue(getClient(), exchange);
break;
case deleteQueue:
deleteQueue(getClient(), exchange);
break;
default:
throw new IllegalArgumentException("Unsupported operation");
}
}
}
public void processSingleMessage(final Exchange exchange) {
String body = exchange.getIn().getBody(String.class);
SendMessageRequest.Builder request = SendMessageRequest.builder().queueUrl(getQueueUrl()).messageBody(body);
request.messageAttributes(translateAttributes(exchange.getIn().getHeaders(), exchange));
addDelay(request, exchange);
configureFifoAttributes(request, exchange);
LOG.trace("Sending request [{}] from exchange [{}]...", request, exchange);
SendMessageResponse result = getClient().sendMessage(request.build());
LOG.trace("Received result [{}]", result);
Message message = getMessageForResponse(exchange);
message.setHeader(Sqs2Constants.MESSAGE_ID, result.messageId());
message.setHeader(Sqs2Constants.MD5_OF_BODY, result.md5OfMessageBody());
}
private void sendBatchMessage(SqsClient amazonSQS, Exchange exchange) {
SendMessageBatchRequest.Builder request = SendMessageBatchRequest.builder().queueUrl(getQueueUrl());
Collection entries = new ArrayList<>();
if (exchange.getIn().getBody() instanceof Iterable) {
Iterable c = exchange.getIn().getBody(Iterable.class);
for (Object o : c) {
String object = (String) o;
SendMessageBatchRequestEntry.Builder entry = SendMessageBatchRequestEntry.builder();
entry.id(UUID.randomUUID().toString());
entry.messageAttributes(translateAttributes(exchange.getIn().getHeaders(), exchange));
entry.messageBody(object);
addDelay(entry, exchange);
configureFifoAttributes(entry, exchange);
entries.add(entry.build());
}
request.entries(entries);
SendMessageBatchResponse result = amazonSQS.sendMessageBatch(request.build());
Message message = getMessageForResponse(exchange);
message.setBody(result);
} else if (exchange.getIn().getBody() instanceof String) {
String c = exchange.getIn().getBody(String.class);
String[] elements = c.split(getConfiguration().getBatchSeparator());
for (String o : elements) {
SendMessageBatchRequestEntry.Builder entry = SendMessageBatchRequestEntry.builder();
entry.id(UUID.randomUUID().toString());
entry.messageAttributes(translateAttributes(exchange.getIn().getHeaders(), exchange));
entry.messageBody(o);
addDelay(entry, exchange);
configureFifoAttributes(entry, exchange);
entries.add(entry.build());
}
request.entries(entries);
SendMessageBatchResponse result = amazonSQS.sendMessageBatch(request.build());
Message message = getMessageForResponse(exchange);
message.setBody(result);
} else {
SendMessageBatchRequest req = exchange.getIn().getBody(SendMessageBatchRequest.class);
SendMessageBatchResponse result = amazonSQS.sendMessageBatch(req);
Message message = getMessageForResponse(exchange);
message.setBody(result);
}
}
private void deleteMessage(SqsClient amazonSQS, Exchange exchange) {
String receiptHandle = exchange.getIn().getHeader(Sqs2Constants.RECEIPT_HANDLE, String.class);
DeleteMessageRequest.Builder request = DeleteMessageRequest.builder();
request.queueUrl(getQueueUrl());
if (ObjectHelper.isEmpty(receiptHandle)) {
throw new IllegalArgumentException("Receipt Handle must be specified for the operation deleteMessage");
}
request.receiptHandle(receiptHandle);
DeleteMessageResponse result = amazonSQS.deleteMessage(request.build());
Message message = getMessageForResponse(exchange);
message.setBody(result);
}
private void listQueues(SqsClient amazonSQS, Exchange exchange) {
ListQueuesRequest.Builder request = ListQueuesRequest.builder();
if (ObjectHelper.isNotEmpty(exchange.getIn().getHeader(Sqs2Constants.SQS_QUEUE_PREFIX))) {
request.queueNamePrefix(exchange.getIn().getHeader(Sqs2Constants.SQS_QUEUE_PREFIX, String.class));
}
ListQueuesResponse result = amazonSQS.listQueues(request.build());
Message message = getMessageForResponse(exchange);
message.setBody(result);
}
private void purgeQueue(SqsClient amazonSQS, Exchange exchange) {
PurgeQueueRequest.Builder request = PurgeQueueRequest.builder();
request.queueUrl(getQueueUrl());
PurgeQueueResponse result = amazonSQS.purgeQueue(request.build());
Message message = getMessageForResponse(exchange);
message.setBody(result);
}
private void deleteQueue(SqsClient amazonSQS, Exchange exchange) {
DeleteQueueRequest.Builder request = DeleteQueueRequest.builder();
request.queueUrl(getQueueUrl());
DeleteQueueResponse result = amazonSQS.deleteQueue(request.build());
Message message = getMessageForResponse(exchange);
message.setBody(result);
}
private void configureFifoAttributes(SendMessageRequest.Builder request, Exchange exchange) {
if (getEndpoint().getConfiguration().isFifoQueue()) {
// use strategies
if (ObjectHelper.isNotEmpty(getEndpoint().getConfiguration().getMessageGroupIdStrategy())) {
MessageGroupIdStrategy messageGroupIdStrategy = getEndpoint().getConfiguration().getMessageGroupIdStrategy();
String messageGroupId = messageGroupIdStrategy.getMessageGroupId(exchange);
request.messageGroupId(messageGroupId);
}
if (ObjectHelper.isNotEmpty(getEndpoint().getConfiguration().getMessageDeduplicationIdStrategy())) {
MessageDeduplicationIdStrategy messageDeduplicationIdStrategy
= getEndpoint().getConfiguration().getMessageDeduplicationIdStrategy();
String messageDeduplicationId = messageDeduplicationIdStrategy.getMessageDeduplicationId(exchange);
request.messageDeduplicationId(messageDeduplicationId);
}
}
}
private void configureFifoAttributes(SendMessageBatchRequestEntry.Builder request, Exchange exchange) {
if (getEndpoint().getConfiguration().isFifoQueue()) {
// use strategies
MessageGroupIdStrategy messageGroupIdStrategy = getEndpoint().getConfiguration().getMessageGroupIdStrategy();
String messageGroupId = messageGroupIdStrategy.getMessageGroupId(exchange);
request.messageGroupId(messageGroupId);
MessageDeduplicationIdStrategy messageDeduplicationIdStrategy
= getEndpoint().getConfiguration().getMessageDeduplicationIdStrategy();
String messageDeduplicationId = messageDeduplicationIdStrategy.getMessageDeduplicationId(exchange);
request.messageDeduplicationId(messageDeduplicationId);
}
}
private void addDelay(SendMessageRequest.Builder request, Exchange exchange) {
Integer headerValue = exchange.getIn().getHeader(Sqs2Constants.DELAY_HEADER, Integer.class);
Integer delayValue;
if (headerValue == null) {
LOG.trace("Using the config delay");
delayValue = getEndpoint().getConfiguration().getDelaySeconds();
} else {
LOG.trace("Using the header delay");
delayValue = headerValue;
}
LOG.trace("found delay: {}", delayValue);
if (delayValue != null) {
request.delaySeconds(delayValue);
}
}
private void addDelay(SendMessageBatchRequestEntry.Builder request, Exchange exchange) {
Integer headerValue = exchange.getIn().getHeader(Sqs2Constants.DELAY_HEADER, Integer.class);
Integer delayValue;
if (headerValue == null) {
LOG.trace("Using the config delay");
delayValue = getEndpoint().getConfiguration().getDelaySeconds();
} else {
LOG.trace("Using the header delay");
delayValue = headerValue;
}
LOG.trace("found delay: {}", delayValue);
if (delayValue != null) {
request.delaySeconds(delayValue);
}
}
protected SqsClient getClient() {
return getEndpoint().getClient();
}
protected String getQueueUrl() {
return getEndpoint().getQueueUrl();
}
protected Sqs2Configuration getConfiguration() {
return getEndpoint().getConfiguration();
}
@Override
public Sqs2Endpoint getEndpoint() {
return (Sqs2Endpoint) super.getEndpoint();
}
@Override
public String toString() {
if (sqsProducerToString == null) {
sqsProducerToString = "SqsProducer[" + URISupport.sanitizeUri(getEndpoint().getEndpointUri()) + "]";
}
return sqsProducerToString;
}
Map translateAttributes(Map headers, Exchange exchange) {
Map result = new HashMap<>();
HeaderFilterStrategy headerFilterStrategy = getEndpoint().getHeaderFilterStrategy();
for (Entry entry : headers.entrySet()) {
// only put the message header which is not filtered into the
// message attribute
if (!headerFilterStrategy.applyFilterToCamelHeaders(entry.getKey(), entry.getValue(), exchange)) {
// We are going to put the first MAX_ATTRIBUTES headers, because this is the maximum Attributes an SQS Message could accept
if (result.size() < MAX_ATTRIBUTES) {
MessageAttributeValue mav = Sqs2MessageHelper.toMessageAttributeValue(entry.getValue());
if (mav != null) {
result.put(entry.getKey(), mav);
}
} else {
String action = getConfiguration().getMessageHeaderExceededLimit();
if ("WARN".equalsIgnoreCase(action) || "WARN_ONCE".equalsIgnoreCase(action)) {
LOG.warn("Cannot put message header with key={} due: {}", entry.getKey(), MAX_MESSAGE);
if ("WARN_ONCE".equalsIgnoreCase(action)) {
break;
}
} else if ("IGNORE".equalsIgnoreCase(action)) {
break;
} else if ("FAIL".equalsIgnoreCase(action)) {
throw new IllegalArgumentException(MAX_MESSAGE);
}
}
}
}
return result;
}
public static Message getMessageForResponse(final Exchange exchange) {
return exchange.getMessage();
}
private Sqs2Operations determineOperation(Exchange exchange) {
Sqs2Operations operation = exchange.getIn().getHeader(Sqs2Constants.SQS_OPERATION, Sqs2Operations.class);
if (operation == null) {
operation = getConfiguration().getOperation();
}
return operation;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy