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

fi.evolver.basics.spring.messaging.sender.aws.SqsSender Maven / Gradle / Ivy

There is a newer version: 6.7.0
Show newest version
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