
fi.evolver.basics.spring.messaging.sender.aws.SqsSender Maven / Gradle / Ivy
package fi.evolver.basics.spring.messaging.sender.aws;
import static fi.evolver.basics.spring.messaging.sender.aws.AwsUtils.STATUS_FAILED;
import static fi.evolver.basics.spring.messaging.sender.aws.AwsUtils.STATUS_OK;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Set;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.amazon.sqs.javamessaging.AmazonSQSExtendedClient;
import com.amazon.sqs.javamessaging.ExtendedClientConfiguration;
import fi.evolver.basics.spring.log.MessageLogService;
import fi.evolver.basics.spring.log.entity.MessageLog.Direction;
import fi.evolver.basics.spring.messaging.SendResult;
import fi.evolver.basics.spring.messaging.entity.Message;
import fi.evolver.basics.spring.messaging.sender.Sender;
import fi.evolver.basics.spring.messaging.util.SendUtils;
import fi.evolver.utils.CommunicationException;
import software.amazon.awssdk.arns.Arn;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.SqsClientBuilder;
@Component
public class SqsSender implements Sender {
private static final Logger LOG = LoggerFactory.getLogger(SqsSender.class);
private static final String PROTOCOL_SQS = "sqs";
private static final String PROPERTY_DELAY_SECONDS = "DelayS";
private static final String PROPERTY_GROUP_ID = "GroupId";
private static final String PROPERTY_S3_BUCKET = "S3Bucket";
private final MessageLogService messageLogService;
@Autowired
public SqsSender(MessageLogService messageLogService) {
this.messageLogService = messageLogService;
}
@Override
public SendResult send(Message message, URI uri) {
return sendMessageToSqs(message, uri);
}
@Override
public Set getSupportedProtocols() {
return Set.of(PROTOCOL_SQS);
}
private SendResult sendMessageToSqs(Message message, URI uri) {
LocalDateTime start = LocalDateTime.now();
String statusCode = STATUS_FAILED;
Arn queue = AwsUtils.parseArn(uri.getSchemeSpecificPart().replaceFirst("^//", ""), "sqs");
AwsCredentialsProvider credentialsProvider = AwsUtils.createCredentialsProvider(message, Region.of(queue.region().get()));
String body = null;
try (Reader reader = new InputStreamReader(message.getDataStream(), StandardCharsets.UTF_8);
SqsClient sqsClient = createSqsClient(queue, message, credentialsProvider)) {
body = IOUtils.toString(reader);
sendToSqs(message, body, queue, credentialsProvider);
statusCode = STATUS_OK;
return SendResult.success();
}
catch (IOException e) {
LOG.warn("SQS send failed", e);
return SendResult.error("SQS send failed: %s", e.getMessage());
}
finally {
messageLogService.logMessage(
start,
message.getMessageType(),
"sqs",
uri.toString(),
messageLogService.getApplicationName(),
message.getTargetSystem(),
Direction.OUTBOUND,
body,
AwsUtils.removeRequestParameterValueMap(message),
null,
null,
statusCode,
null,
SendUtils.mapMetadata(message.getMetadata()));
}
}
public static void sendToSqs(Message message, String text, Arn queue, AwsCredentialsProvider credentialsProvider)
throws CommunicationException {
boolean fifo = queue.resourceAsString().endsWith(".fifo");
int delaySeconds = AwsUtils.getIntegerParameter(message, PROPERTY_DELAY_SECONDS, fifo ? null : 5);
try (SqsClient sqsClient = createSqsClient(queue, message, credentialsProvider)) {
String groupId = AwsUtils.getStringParameter(message, PROPERTY_GROUP_ID, fifo ? "default" : null);
String queueUrl = sqsClient.getQueueUrl(b -> b.queueName(queue.resource().resource()).build()).queueUrl();
if (fifo) {
sqsClient.sendMessage(b -> b
.queueUrl(queueUrl)
.messageGroupId(groupId)
.messageDeduplicationId("%s-%s".formatted(message.getMessageChainId(), message.getId()))
.messageBody(text)
.build());
}
else {
sqsClient.sendMessage(b -> b
.queueUrl(queueUrl)
.delaySeconds(delaySeconds)
.messageBody(text)
.build());
}
}
catch (Exception e) {
throw new CommunicationException(e, "Failed sending message to SQS");
}
}
private static SqsClient createSqsClient(Arn queue, Message message, AwsCredentialsProvider credentialsProvider) throws CommunicationException {
Region region = Region.of(queue.region().get());
String s3Bucket = AwsUtils.getStringParameter(message, PROPERTY_S3_BUCKET, null);
SqsClient result = buildSqsClient(queue, credentialsProvider);
if (s3Bucket != null) {
S3Client s3Client = S3Client.builder()
.endpointOverride(AwsUtils.getEndpointOverride().orElse(null))
.region(region)
.credentialsProvider(credentialsProvider)
.forcePathStyle(true)
.build();
ExtendedClientConfiguration clientConfiguration = new ExtendedClientConfiguration();
clientConfiguration.setPayloadSupportEnabled(s3Client, s3Bucket);
result = new AmazonSQSExtendedClient(result, clientConfiguration);
}
return result;
}
private static SqsClient buildSqsClient(Arn queue, AwsCredentialsProvider credentialsProvider) throws CommunicationException {
SqsClientBuilder builder = SqsClient.builder()
.credentialsProvider(credentialsProvider);
URI override = AwsUtils.getEndpointOverride().orElse(null);
if (override != null) {
builder.endpointOverride(override);
}
else {
builder.region(queue.region().map(Region::of).orElse(Region.AWS_GLOBAL));
}
return builder.build();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy