diff --git a/.doc_gen/metadata/sqs_metadata.yaml b/.doc_gen/metadata/sqs_metadata.yaml index 257d4e038ba..0771a1e3cec 100644 --- a/.doc_gen/metadata/sqs_metadata.yaml +++ b/.doc_gen/metadata/sqs_metadata.yaml @@ -1116,7 +1116,7 @@ sqs_Scenario_TopicsAndQueues: sqs_Scenario_WorkWithTags: title: Work with queue tags and &SQS; using an &AWS; SDK title_abbrev: Work with queue tags - synopsis: perform tagging operation with &SQS; + synopsis: perform tagging operation with &SQS;. category: Scenarios languages: Java: @@ -1130,3 +1130,68 @@ sqs_Scenario_WorkWithTags: - sqs.java2.tag-examples services: sqs: {TagQueue, ListQueueTags, UntagQueue} +sqs_Scenario_UseJMS: + title: Use the &SQS; Java Messaging Library to work with the Java Message Service (JMS) interface for &SQS; + title_abbrev: Use the &SQS; Java Messaging Library to work with the JMS interface + synopsis: use the &SQS; Java Messaging Library to work with the JMS interface. + category: Scenarios + languages: + Java: + versions: + - sdk_version: 2 + github: javav2/example_code/sqs + sdkguide: + excerpts: + - description: >- + The following examples work with standard &SQS; queues and include: + + + Sending a text message. + + + Receiving messages synchronously. + + + Receiving messages asynchronously. + + + Receiving messages using CLIENT_ACKNOWLEDGE mode. + + + Receiving messages using the UNORDERED_ACKNOWLEDGE mode. + + + Using Spring to inject dependencies. + + + A utility class that provides common methods used by the other examples. + + + For more information on using JMS with &SQS;, see the + &SQS; Developer Guide. + Sending a text message. + snippet_tags: + - sqs-jms.java2.send-text-message + - description: Receiving messages synchronously. + snippet_tags: + - sqs-jms.java2.receive-message-sync + - description: Receiving messages asynchronously. + snippet_tags: + - sqs-jms.java2.receive-message-async + - description: Receiving messages using CLIENT_ACKNOWLEDGE mode. + snippet_tags: + - sqs-jms.java2.receive-message-sync-client-ack + - description: Receiving messages using the UNORDERED_ACKNOWLEDGE mode. + snippet_tags: + - sqs-jms.java2.receive-message-sync-unordered-ack + - description: Using Spring to inject dependencies. + snippet_tags: + - sqs-jms.java2.spring + - description: Spring bean definitions. + snippet_files: + - javav2/example_code/sqs-jms/src/main/resources/SpringExampleConfiguration.xml.txt + - description: A utility class that provides common methods used by the other examples. + snippet_files: + - javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/SqsJmsExampleUtils.java + services: + sqs: {CreateQueue, DeleteQueue} diff --git a/javav2/example_code/sqs-jms/pom.xml b/javav2/example_code/sqs-jms/pom.xml new file mode 100644 index 00000000000..f9d13824bb4 --- /dev/null +++ b/javav2/example_code/sqs-jms/pom.xml @@ -0,0 +1,124 @@ + + + 4.0.0 + SQSJMSJ2Project + SQSJMSJ2Project + 1.0-SNAPSHOT + + UTF-8 + 17 + 17 + 17 + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.5.2 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + ${java.version} + ${java.version} + + + + + + + + software.amazon.awssdk + bom + 2.29.24 + pom + import + + + org.apache.logging.log4j + log4j-bom + 2.23.1 + pom + import + + + + + + com.amazonaws + amazon-sqs-java-messaging-lib + 2.1.4 + + + software.amazon.awssdk + sso + + + software.amazon.awssdk + ssooidc + + + org.apache.logging.log4j + log4j-core + + + org.slf4j + slf4j-api + 2.0.13 + + + org.apache.logging.log4j + log4j-slf4j2-impl + + + org.apache.logging.log4j + log4j-1.2-api + + + + org.springframework + spring-context + 6.1.14 + + + + + org.springframework + spring-beans + 6.1.14 + + + + + org.springframework + spring-core + 6.1.14 + + + org.junit.jupiter + junit-jupiter-engine + 5.12.0 + test + + + + + software.amazon.awssdk + apache-client + + + commons-logging + commons-logging + + + + + + \ No newline at end of file diff --git a/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/SqsJmsExampleUtils.java b/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/SqsJmsExampleUtils.java new file mode 100644 index 00000000000..71eba0e25cf --- /dev/null +++ b/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/SqsJmsExampleUtils.java @@ -0,0 +1,210 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.sqs.jms; + +import com.amazon.sqs.javamessaging.AmazonSQSMessagingClientWrapper; +import com.amazon.sqs.javamessaging.ProviderConfiguration; +import com.amazon.sqs.javamessaging.SQSConnection; +import com.amazon.sqs.javamessaging.SQSConnectionFactory; +import jakarta.jms.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.core.exception.SdkException; +import software.amazon.awssdk.services.sqs.SqsClient; +import software.amazon.awssdk.services.sqs.model.CreateQueueRequest; +import software.amazon.awssdk.services.sqs.model.QueueAttributeName; + +import java.time.Duration; +import java.util.Base64; +import java.util.Map; + +/** + * This utility class provides helper methods for working with Amazon Simple Queue Service (Amazon SQS) + * through the Java Message Service (JMS) interface. It contains common operations for managing message + * queues and handling message delivery. + */ +public class SqsJmsExampleUtils { + private static final Logger LOGGER = LoggerFactory.getLogger(SqsJmsExampleUtils.class); + public static final Long QUEUE_VISIBILITY_TIMEOUT = 5L; + + /** + * This method verifies that a message queue exists and creates it if necessary. The method checks for + * an existing queue first to optimize performance. + * + * @param connection The active connection to the messaging service + * @param queueName The name of the queue to verify or create + * @param visibilityTimeout The duration in seconds that messages will be hidden after being received + * @throws JMSException If there is an error accessing or creating the queue + */ + public static void ensureQueueExists(SQSConnection connection, String queueName, Long visibilityTimeout) throws JMSException { + AmazonSQSMessagingClientWrapper client = connection.getWrappedAmazonSQSClient(); + + /* In most cases, you can do this with just a 'createQueue' call, but 'getQueueUrl' + (called by 'queueExists') is a faster operation for the common case where the queue + already exists. Also, many users and roles have permission to call 'getQueueUrl' + but don't have permission to call 'createQueue'. + */ + if( !client.queueExists(queueName) ) { + CreateQueueRequest createQueueRequest = CreateQueueRequest.builder() + .queueName(queueName) + .attributes(Map.of(QueueAttributeName.VISIBILITY_TIMEOUT, String.valueOf(visibilityTimeout))) + .build(); + client.createQueue( createQueueRequest ); + } + } + + /** + * This method sends a simple text message to a specified message queue. It handles all necessary + * setup for the message delivery process. + * + * @param session The active messaging session used to create and send the message + * @param queueName The name of the queue where the message will be sent + */ + public static void sendTextMessage(Session session, String queueName) { + // Rest of implementation... + + try { + MessageProducer producer = session.createProducer( session.createQueue( queueName) ); + Message message = session.createTextMessage("Hello world!"); + producer.send(message); + } catch (JMSException e) { + LOGGER.error( "Error receiving from SQS", e ); + } + } + + /** + * This method processes incoming messages and logs their content based on the message type. + * It supports text messages, binary data, and Java objects. + * + * @param message The message to be processed and logged + * @throws JMSException If there is an error reading the message content + */ + public static void handleMessage(Message message) throws JMSException { + // Rest of implementation... + LOGGER.info( "Got message {}", message.getJMSMessageID() ); + LOGGER.info( "Content: "); + if(message instanceof TextMessage txtMessage) { + LOGGER.info( "\t{}", txtMessage.getText() ); + } else if(message instanceof BytesMessage byteMessage){ + // Assume the length fits in an int - SQS only supports sizes up to 256k so that + // should be true + byte[] bytes = new byte[(int)byteMessage.getBodyLength()]; + byteMessage.readBytes(bytes); + LOGGER.info( "\t{}", Base64.getEncoder().encodeToString( bytes ) ); + } else if( message instanceof ObjectMessage) { + ObjectMessage objMessage = (ObjectMessage) message; + LOGGER.info( "\t{}", objMessage.getObject() ); + } + } + + /** + * This method sets up automatic message processing for a specified queue. It creates a listener + * that will receive and handle incoming messages without blocking the main program. + * + * @param session The active messaging session + * @param queueName The name of the queue to monitor + * @param connection The active connection to the messaging service + */ + public static void receiveMessagesAsync(Session session, String queueName, Connection connection) { + // Rest of implementation... + try { + // Create a consumer for the queue. + MessageConsumer consumer = session.createConsumer(session.createQueue(queueName)); + // Provide an implementation of the MessageListener interface, which has a single 'onMessage' method. + // We use a lambda expression for the implementation. + consumer.setMessageListener(message -> { + try { + SqsJmsExampleUtils.handleMessage(message); + message.acknowledge(); + } catch (JMSException e) { + LOGGER.error("Error processing message: {}", e.getMessage()); + } + }); + // Start receiving incoming messages. + connection.start(); + } catch (JMSException e) { + throw new RuntimeException(e); + } + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + + /** + * This method performs cleanup operations after message processing is complete. It receives + * any messages in the specified queue, removes the message queue and closes all + * active connections to prevent resource leaks. + * + * @param queueName The name of the queue to be removed + * @param visibilityTimeout The duration in seconds that messages are hidden after being received + * @throws JMSException If there is an error during the cleanup process + */ + public static void cleanUpExample(String queueName, Long visibilityTimeout) throws JMSException { + LOGGER.info("Performing cleanup."); + + SQSConnectionFactory connectionFactory = new SQSConnectionFactory( + new ProviderConfiguration(), + SqsClient.create() + ); + + try (SQSConnection connection = connectionFactory.createConnection() ) { + ensureQueueExists(connection, queueName, visibilityTimeout); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + receiveMessagesAsync(session, queueName, connection); + + SqsClient sqsClient = connection.getWrappedAmazonSQSClient().getAmazonSQSClient(); + try { + String queueUrl = sqsClient.getQueueUrl(b -> b.queueName(queueName)).queueUrl(); + sqsClient.deleteQueue(b -> b.queueUrl(queueUrl)); + LOGGER.info("Queue deleted: {}", queueUrl); + } catch (SdkException e) { + LOGGER.error("Error during SQS operations: ", e); + } + } + LOGGER.info("Clean up: Connection closed"); + } + + /** + * This method creates a background task that sends multiple messages to a specified queue + * after waiting for a set time period. The task operates independently to ensure efficient + * message processing without interrupting other operations. + * + * @param queueName The name of the queue where messages will be sent + * @param secondsToWait The number of seconds to wait before sending messages + * @param numMessages The number of messages to send + * @param visibilityTimeout The duration in seconds that messages remain hidden after being received + * @return A task that can be executed to send the messages + */ + public static Runnable sendAMessageAsync(String queueName, Long secondsToWait, Integer numMessages, Long visibilityTimeout) { + return () -> { + try { + Thread.sleep(Duration.ofSeconds(secondsToWait).toMillis()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + try { + SQSConnectionFactory connectionFactory = new SQSConnectionFactory( + new ProviderConfiguration(), + SqsClient.create() + ); + try (SQSConnection connection = connectionFactory.createConnection()) { + ensureQueueExists(connection, queueName, visibilityTimeout); + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + for (int i = 1; i <= numMessages; i++) { + MessageProducer producer = session.createProducer(session.createQueue(queueName)); + producer.send(session.createTextMessage("Hello World " + i + "!")); + } + } + } catch (JMSException e) { + LOGGER.error(e.getMessage(), e); + throw new RuntimeException(e); + } + }; + } +} diff --git a/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/basic/JmsSqsSyncFifo.java b/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/basic/JmsSqsSyncFifo.java new file mode 100644 index 00000000000..d38d26d69e3 --- /dev/null +++ b/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/basic/JmsSqsSyncFifo.java @@ -0,0 +1,102 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.sqs.jms.basic; + +import com.amazon.sqs.javamessaging.AmazonSQSMessagingClientWrapper; +import com.amazon.sqs.javamessaging.ProviderConfiguration; +import com.amazon.sqs.javamessaging.SQSConnection; +import com.amazon.sqs.javamessaging.SQSConnectionFactory; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageProducer; +import jakarta.jms.Queue; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import org.slf4j.Logger; +import software.amazon.awssdk.services.sqs.SqsClient; +import software.amazon.awssdk.services.sqs.model.CreateQueueRequest; +import software.amazon.awssdk.services.sqs.model.QueueAttributeName; + +import java.util.Map; +import java.util.UUID; + +public class JmsSqsSyncFifo { + private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(JmsSqsSyncFifo.class); + private static final String QUEUE_NAME = "MyQueue-" + UUID.randomUUID() + ".fifo"; + + public static void main(String[] args) { + // Create a new connection factory with all defaults (credentials and region) set automatically. + SQSConnectionFactory connectionFactory = new SQSConnectionFactory( + new ProviderConfiguration(), + SqsClient.create() + ); + try { + // Create the connection. + SQSConnection connection = connectionFactory.createConnection(); + // snippet-start:[sqs-jms.java2.jms-basics.create-fifo-queue] + // Get the wrapped client. + AmazonSQSMessagingClientWrapper client = connection.getWrappedAmazonSQSClient(); + // Create an Amazon SQS FIFO queue, if it doesn't already exist. FIFO queue names must end in '.fifo'. + if (!client.queueExists(QUEUE_NAME)) { + Map attributes2 = Map.of( + QueueAttributeName.FIFO_QUEUE, "true", + QueueAttributeName.CONTENT_BASED_DEDUPLICATION, "true" + ); + client.createQueue(CreateQueueRequest.builder() + .queueName(QUEUE_NAME) + .attributes(attributes2) + .build()); + } + // snippet-end:[sqs-jms.java2.jms-basics.create-fifo-queue] + + // Create a non-transacted session in AUTO_ACKNOWLEDGE mode. + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + // Create a queue identity and specify the queue name to the session. + Queue queue = session.createQueue(QUEUE_NAME); + // Create a producer for the queue. + MessageProducer producer = session.createProducer(queue); + // snippet-start:[sqs-jms.java2.jms-basics.send-text-message-fifo] + // Create a text message. + TextMessage message = session.createTextMessage("Hello World!"); + // Set the message group ID. + message.setStringProperty("JMSXGroupID", "Default"); + + // You can also set a custom message deduplication ID. For example, + // `message.setStringProperty("JMS_SQS_DeduplicationId", "hello");` + // We don't need it for this example because content-based deduplication is enabled for the queue. + + // Send the message. + producer.send(message); + LOGGER.info("JMS Message {}", message.getJMSMessageID()); + LOGGER.info("JMS Message Sequence Number {}", message.getStringProperty("JMS_SQS_SequenceNumber")); + // snippet-end:[sqs-jms.java2.jms-basics.send-text-message-fifo] + + // Create a consumer for the queue. + MessageConsumer consumer = session.createConsumer(queue); + // Start receiving incoming messages. + connection.start(); + // snippet-start:[sqs-jms.java2.jms-basics.receive-msg-fifo-sync] + // Receive a message from the queue and wait up to 1 second. + Message receivedMessage = consumer.receive(1000); + // Cast the received message as a 'TextMessage' and display the text. + if (receivedMessage != null) { + LOGGER.info("Received: {}", ((TextMessage) receivedMessage).getText()); + LOGGER.info("Group id: {}", receivedMessage.getStringProperty("JMSXGroupID")); + LOGGER.info("Message deduplication id: {}", receivedMessage.getStringProperty("JMS_SQS_DeduplicationId")); + LOGGER.info("Message sequence number: {}", receivedMessage.getStringProperty("JMS_SQS_SequenceNumber")); + } + // snippet-end:[sqs-jms.java2.jms-basics.receive-msg-fifo-sync] + SqsClient sqsClient = connection.getWrappedAmazonSQSClient().getAmazonSQSClient(); + String queueUrl = connection.getWrappedAmazonSQSClient().getQueueUrl(QUEUE_NAME).queueUrl(); + // Close the connection (and the session). + connection.close(); + if (queueUrl != null){ + sqsClient.deleteQueue(b -> b.queueUrl(queueUrl)); + } + } catch (JMSException e) { + throw new RuntimeException(e); + } + } +} diff --git a/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/basic/JmsSqsSyncStandard.java b/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/basic/JmsSqsSyncStandard.java new file mode 100644 index 00000000000..63cf28c767c --- /dev/null +++ b/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/basic/JmsSqsSyncStandard.java @@ -0,0 +1,250 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.sqs.jms.basic; + +import com.amazon.sqs.javamessaging.AmazonSQSMessagingClientWrapper; +import com.amazon.sqs.javamessaging.ProviderConfiguration; +import com.amazon.sqs.javamessaging.SQSConnection; +import com.amazon.sqs.javamessaging.SQSConnectionFactory; +import com.amazon.sqs.javamessaging.SQSSession; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageProducer; +import jakarta.jms.Queue; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.services.sqs.SqsClient; + +import java.util.UUID; + +public class JmsSqsSyncStandard { + private static final Logger LOGGER = LoggerFactory.getLogger(JmsSqsSyncStandard.class); + private static final String QUEUE_NAME = "MyQueue" + UUID.randomUUID(); + private static int ACKNOWLEDGE_MODE; + private static String RECEIVE_MODE; + + + /** This code example helps you get started using the SQS JMS client. Learn how to use the Java Message Service (JMS) + * with Amazon SQS. Create connections, send and receive messages, and implement asynchronous message handling. + * + * @param args Provide'-acknowledge-mode [ack-mode]' and '-receive-mode [receive-mode]' as program arguments. + * Valid values for [ack-mode] are 'auto', 'client' and 'unordered'. Values for [receive-mode] are 'sync' and 'async'. + * Example: -acknowledge-mode unordered -receive-mode sync + * Example: -acknowledge-mode client -receive-mode async + * If you don't provide program arguments, the defaults are `-acknowledge-mode unordered -receive-mode sync`. + */ + public static void main(String[] args) { + parseProgramArgs(args); + // snippet-start:[sqs-jms.java2.jms-basics.create-conn-factory] + // Create a new connection factory with all defaults (credentials and region) set automatically. + SQSConnectionFactory connectionFactory = new SQSConnectionFactory( + new ProviderConfiguration(), + SqsClient.create() + ); + // snippet-end:[sqs-jms.java2.jms-basics.create-conn-factory] + try { + // snippet-start:[sqs-jms.java2.jms-basics.create-conn] + // Create the connection. + SQSConnection connection = connectionFactory.createConnection(); + // snippet-end:[sqs-jms.java2.jms-basics.create-conn] + + // snippet-start:[sqs-jms.java2.jms-basics.create-std-queue] + // Get the wrapped client. + AmazonSQSMessagingClientWrapper client = connection.getWrappedAmazonSQSClient(); + // Create an SQS queue named 'MyQueue', if it doesn't already exist. + if (!client.queueExists(QUEUE_NAME)) { + client.createQueue(QUEUE_NAME); + } + // snippet-end:[sqs-jms.java2.jms-basics.create-std-queue] + + + Session session; + if (RECEIVE_MODE.equals("sync")) { + session = switch (ACKNOWLEDGE_MODE) { + case Session.AUTO_ACKNOWLEDGE -> createAutoAcknowledgeSession(connection); + case Session.CLIENT_ACKNOWLEDGE -> createClientAcknowledgeSession(connection); + case SQSSession.UNORDERED_ACKNOWLEDGE -> createUnorderedAcknowledgeSession(connection); + default -> throw new IllegalStateException("Unexpected value: " + ACKNOWLEDGE_MODE); + }; + } else { + session = createAutoAcknowledgeSession(connection); + } + // snippet-start:[sqs-jms.java2.jms-basics.create-send-setup] + // Create a queue identity and specify the queue name to the session. + Queue queue = session.createQueue(QUEUE_NAME); + // Create a producer for queue. + MessageProducer producer = session.createProducer(queue); + // snippet-end:[sqs-jms.java2.jms-basics.create-send-setup] + + // snippet-start:[sqs-jms.java2.jms-basics.send-text-message-std] + // Create the text message. + TextMessage message = session.createTextMessage("Hello World!"); + // Send the message. + producer.send(message); + LOGGER.info("JMS Message {}", message.getJMSMessageID()); + // snippet-end:[sqs-jms.java2.jms-basics.send-text-message-std] + + switch (RECEIVE_MODE) { + case "sync" -> { + switch (ACKNOWLEDGE_MODE) { + case Session.AUTO_ACKNOWLEDGE -> receiveMessageAutoAckSync(connection, session, queue); + case Session.CLIENT_ACKNOWLEDGE -> receiveMessageExplicitAckSync(connection, session, queue); + case SQSSession.UNORDERED_ACKNOWLEDGE -> receiveMessageExplicitAckSync(connection, session, queue); + } + } + case "async" -> receiveMessageAutoAckAsync(connection, session, queue); + } + SqsClient sqsClient = connection.getWrappedAmazonSQSClient().getAmazonSQSClient(); + String queueUrl = connection.getWrappedAmazonSQSClient().getQueueUrl(QUEUE_NAME).queueUrl(); + if (queueUrl != null){ + sqsClient.deleteQueue(b -> b.queueUrl(queueUrl)); + } + // snippet-start:[sqs-jms.java2.jms-basics.close-conn] + // Close the connection (and the session). + connection.close(); + // snippet-end:[sqs-jms.java2.jms-basics.close-conn] + } catch (JMSException e) { + throw new RuntimeException(e); + } + } + + static Session createAutoAcknowledgeSession(SQSConnection connection) { + try { + // snippet-start:[sqs-jms.java2.jms-basics.create-session-auto-ack] + // Create the non-transacted session with AUTO_ACKNOWLEDGE mode. + return connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + // snippet-end:[sqs-jms.java2.jms-basics.create-session-auto-ack] + } catch (JMSException e) { + throw new RuntimeException(e); + } + } + + static Session createClientAcknowledgeSession(SQSConnection connection) { + try { + // snippet-start:[sqs-jms.java2.jms-basics.create-session-client-ack] + // Create the non-transacted session with CLIENT_ACKNOWLEDGE mode. + return connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + // snippet-end:[sqs-jms.java2.jms-basics.create-session-client-ack] + } catch (JMSException e) { + throw new RuntimeException(e); + } + } + + static Session createUnorderedAcknowledgeSession(SQSConnection connection) { + try { + // snippet-start:[sqs-jms.java2.jms-basics.create-session-unordered-ack] + // Create the non-transacted session with UNORDERED_ACKNOWLEDGE mode. + return connection.createSession(false, SQSSession.UNORDERED_ACKNOWLEDGE); + // snippet-end:[sqs-jms.java2.jms-basics.create-session-unordered-ack] + } catch (JMSException e) { + throw new RuntimeException(e); + } + } + + static void receiveMessageAutoAckSync(SQSConnection connection, Session session, Queue queue) { + try { + // snippet-start:[sqs-jms.java2.jms-basics.receive-setup-std-sync] + // Create a consumer for the queue. + MessageConsumer consumer = session.createConsumer(queue); + // Start receiving incoming messages. + connection.start(); + // snippet-end:[sqs-jms.java2.jms-basics.receive-setup-std-sync] + // snippet-start:[sqs-jms.java2.jms-basics.receive-msg-std-sync] + // Receive a message from the queue and wait up to 1 second. + Message receivedMessage = consumer.receive(1000); + + // Cast the received message as a 'TextMessage' and display the text. + if (receivedMessage != null) { + LOGGER.info("Received: {}", ((TextMessage) receivedMessage).getText()); + } + // snippet-end:[sqs-jms.java2.jms-basics.receive-msg-std-sync] + } catch (JMSException e) { + throw new RuntimeException(e); + } + } + + static void receiveMessageExplicitAckSync(SQSConnection connection, Session session, Queue queue) { + try { + // Create a consumer for the queue. + MessageConsumer consumer = session.createConsumer(queue); + // Start receiving incoming messages. + connection.start(); + // Receive a message from the queue and wait up to 1 second. + Message receivedMessage = consumer.receive(1000); + // snippet-start:[sqs-jms.java2.jms-basics.receive-msg-client-ack] + // Cast the received message as a 'TextMessage' and display the text. + if (receivedMessage != null) { + LOGGER.info("Received: {}", ((TextMessage) receivedMessage).getText()); + receivedMessage.acknowledge(); + LOGGER.info("Acknowledged: {}", receivedMessage.getJMSMessageID()); + } + // snippet-end:[sqs-jms.java2.jms-basics.receive-msg-client-ack] + } catch (JMSException e) { + throw new RuntimeException(e); + } + } + + static void receiveMessageAutoAckAsync(SQSConnection connection, Session session, Queue queue) { + // snippet-start:[sqs-jms.java2.jms-basics.receive-async] + try { + // Create a consumer for the queue. + MessageConsumer consumer = session.createConsumer(queue); + // Provide an implementation of the MessageListener interface, which has a single 'onMessage' method. + // We use a lambda expression for the implementation. + consumer.setMessageListener(message -> { + try { + // Cast the received message as TextMessage and print the text to screen. + LOGGER.info("Received: {}", ((TextMessage) message).getText()); + } catch (JMSException e) { + LOGGER.error("Error processing message: {}", e.getMessage()); + } + }); + // Start receiving incoming messages. + connection.start(); + } catch (JMSException e) { + throw new RuntimeException(e); + } + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + // snippet-end:[sqs-jms.java2.jms-basics.receive-async] + } + + static void parseProgramArgs(String[] args) { + for (int i = 0; i < args.length; i++) { + switch (args[i]) { + case "-acknowledge-mode": + if (i + 1 < args.length) { + switch (args[i + 1]) { + case "auto" -> ACKNOWLEDGE_MODE = Session.AUTO_ACKNOWLEDGE; + case "client" -> ACKNOWLEDGE_MODE = Session.CLIENT_ACKNOWLEDGE; + case "unordered" -> ACKNOWLEDGE_MODE = SQSSession.UNORDERED_ACKNOWLEDGE; + } + i++; + } + break; + case "-receive-mode": + if (i + 1 < args.length) { + switch (args[i + 1]){ + case "sync" -> RECEIVE_MODE = "sync"; + case "async" -> RECEIVE_MODE = "async"; + } + i++; + } + break; + } + } + if (ACKNOWLEDGE_MODE == 0) { + ACKNOWLEDGE_MODE = Session.AUTO_ACKNOWLEDGE; + } + if (RECEIVE_MODE == null) { + RECEIVE_MODE = "sync"; + } + } +} diff --git a/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/spring/SpringExample.java b/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/spring/SpringExample.java new file mode 100644 index 00000000000..8048c89ff84 --- /dev/null +++ b/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/spring/SpringExample.java @@ -0,0 +1,117 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// snippet-start:[sqs-jms.java2.spring] +package com.example.sqs.jms.spring; + +import com.amazon.sqs.javamessaging.SQSConnection; +import com.example.sqs.jms.SqsJmsExampleUtils; +import jakarta.jms.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.context.support.FileSystemXmlApplicationContext; + +import java.io.File; +import java.net.URL; +import java.util.concurrent.TimeUnit; + +/** + * Demonstrates how to send and receive messages using the Amazon SQS Java Messaging Library + * with Spring Framework integration. This example connects to a standard Amazon SQS message + * queue using Spring's dependency injection to configure the connection and messaging components. + * The application uses the JMS (Java Message Service) API to handle message operations. + */ +public class SpringExample { + private static final Integer POLLING_SECONDS = 15; + private static final String SPRING_XML_CONFIG_FILE = "SpringExampleConfiguration.xml.txt"; + private static final Logger LOGGER = LoggerFactory.getLogger(SpringExample.class); + + /** + * Demonstrates sending and receiving messages through a standard Amazon SQS message queue + * using Spring Framework configuration. This method loads connection settings from an XML file, + * establishes a messaging session using the Amazon SQS Java Messaging Library, and processes + * messages using JMS (Java Message Service) operations. If the queue doesn't exist, it will + * be created automatically. + * + * @param args Command line arguments (not used) + */ + public static void main(String[] args) { + + URL resource = SpringExample.class.getClassLoader().getResource(SPRING_XML_CONFIG_FILE); + File springFile = new File(resource.getFile()); + if (!springFile.exists() || !springFile.canRead()) { + LOGGER.error("File " + SPRING_XML_CONFIG_FILE + " doesn't exist or isn't readable."); + System.exit(1); + } + + try (FileSystemXmlApplicationContext context = + new FileSystemXmlApplicationContext("file://" + springFile.getAbsolutePath())) { + + Connection connection; + try { + connection = context.getBean(Connection.class); + } catch (NoSuchBeanDefinitionException e) { + LOGGER.error("Can't find the JMS connection to use: " + e.getMessage(), e); + System.exit(2); + return; + } + + String queueName; + try { + queueName = context.getBean("queueName", String.class); + } catch (NoSuchBeanDefinitionException e) { + LOGGER.error("Can't find the name of the queue to use: " + e.getMessage(), e); + System.exit(3); + return; + } + try { + if (connection instanceof SQSConnection) { + SqsJmsExampleUtils.ensureQueueExists((SQSConnection) connection, queueName, SqsJmsExampleUtils.QUEUE_VISIBILITY_TIMEOUT); + } + // Create the JMS session. + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + SqsJmsExampleUtils.sendTextMessage(session, queueName); + MessageConsumer consumer = session.createConsumer(session.createQueue(queueName)); + + receiveMessages(consumer); + } catch (JMSException e) { + LOGGER.error(e.getMessage(), e); + throw new RuntimeException(e); + } + } // Spring context autocloses. Managed Spring beans that implement AutoClosable, such as the + // 'connection' bean, are also closed. + LOGGER.info("Context closed"); + } + + /** + * Continuously checks for and processes messages from a standard Amazon SQS message queue + * using the Amazon SQS Java Messaging Library underlying the JMS API. This method waits for incoming messages, + * processes them when they arrive, and acknowledges their receipt using JMS (Java Message + * Service) operations. The method will stop checking for messages after 15 seconds of + * inactivity. + * + * @param consumer The JMS message consumer used to receive messages from the queue + */ + private static void receiveMessages(MessageConsumer consumer) { + try { + while (true) { + LOGGER.info("Waiting for messages..."); + // Wait 15 seconds for a message. + Message message = consumer.receive(TimeUnit.SECONDS.toMillis(POLLING_SECONDS)); + if (message == null) { + LOGGER.info("Shutting down after {} seconds of silence.", POLLING_SECONDS); + break; + } + SqsJmsExampleUtils.handleMessage(message); + message.acknowledge(); + LOGGER.info("Message acknowledged."); + } + } catch (JMSException e) { + LOGGER.error("Error receiving from SQS.", e); + } + } +} +// snippet-end:[sqs-jms.java2.spring] + diff --git a/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/stdqueue/AsyncMessageReceiver.java b/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/stdqueue/AsyncMessageReceiver.java new file mode 100644 index 00000000000..79ff08b068a --- /dev/null +++ b/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/stdqueue/AsyncMessageReceiver.java @@ -0,0 +1,97 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.sqs.jms.stdqueue; + +import com.amazon.sqs.javamessaging.ProviderConfiguration; +import com.amazon.sqs.javamessaging.SQSConnection; +import com.amazon.sqs.javamessaging.SQSConnectionFactory; +import com.example.sqs.jms.SqsJmsExampleUtils; +import jakarta.jms.JMSException; +import jakarta.jms.MessageConsumer; +import jakarta.jms.Session; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.services.sqs.SqsClient; + +import java.util.UUID; + +/** + * This class demonstrates non-blocking message processing with a standard Amazon SQS queue + * using the Amazon SQS Java Messaging Library. It shows how to receive and process messages + * automatically as they arrive using JMS (Java Message Service) event listeners, allowing + * the application to perform other tasks while waiting for messages. + */ +public class AsyncMessageReceiver { + private static final Logger LOGGER = LoggerFactory.getLogger(AsyncMessageReceiver.class); + public static final String QUEUE_NAME = "SQSJMSClientExampleQueue" + UUID.randomUUID(); + + public static void main(String[] args){ + try { + new Thread(SqsJmsExampleUtils.sendAMessageAsync(QUEUE_NAME, 3L, 5, SqsJmsExampleUtils.QUEUE_VISIBILITY_TIMEOUT)).start(); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } + try { + doReceiveMessageAsync(); + SqsJmsExampleUtils.cleanUpExample(QUEUE_NAME, SqsJmsExampleUtils.QUEUE_VISIBILITY_TIMEOUT ); + } catch (JMSException e) { + LOGGER.error(e.getMessage(), e); + } + } + + // snippet-start:[sqs-jms.java2.receive-message-async] + /** + * This method sets up automatic message handling for a standard Amazon SQS queue using the + * Amazon SQS Java Messaging Library. It creates a listener that processes messages as soon + * as they arrive using JMS (Java Message Service), runs for 5 seconds, then cleans up all + * messaging resources. + * + * @throws JMSException If there is a problem connecting to or receiving messages from the queue + */ + public static void doReceiveMessageAsync() throws JMSException { + // Create a connection factory. + SQSConnectionFactory connectionFactory = new SQSConnectionFactory( + new ProviderConfiguration(), + SqsClient.create() + ); + + // Create a connection. + try (SQSConnection connection = connectionFactory.createConnection() ) { + + // Create the queue if needed. + SqsJmsExampleUtils.ensureQueueExists(connection, QUEUE_NAME, SqsJmsExampleUtils.QUEUE_VISIBILITY_TIMEOUT); + + // Create a session. + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + try { + // Create a consumer for the queue. + MessageConsumer consumer = session.createConsumer(session.createQueue(QUEUE_NAME)); + // Provide an implementation of the MessageListener interface, which has a single 'onMessage' method. + // We use a lambda expression for the implementation. + consumer.setMessageListener(message -> { + try { + SqsJmsExampleUtils.handleMessage(message); + message.acknowledge(); + } catch (JMSException e) { + LOGGER.error("Error processing message: {}", e.getMessage()); + } + }); + // Start receiving incoming messages. + connection.start(); + LOGGER.info("Waiting for messages..."); + } catch (JMSException e) { + throw new RuntimeException(e); + } + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } // The connection closes automatically. This also closes the session. + LOGGER.info( "Connection closed" ); + } + // snippet-end:[sqs-jms.java2.receive-message-async] + +} diff --git a/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/stdqueue/SyncMessageReceiver.java b/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/stdqueue/SyncMessageReceiver.java new file mode 100644 index 00000000000..6cc4fb95ff8 --- /dev/null +++ b/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/stdqueue/SyncMessageReceiver.java @@ -0,0 +1,106 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.sqs.jms.stdqueue; + +import com.amazon.sqs.javamessaging.ProviderConfiguration; +import com.amazon.sqs.javamessaging.SQSConnection; +import com.amazon.sqs.javamessaging.SQSConnectionFactory; +import com.example.sqs.jms.SqsJmsExampleUtils; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.Session; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.services.sqs.SqsClient; + +import java.time.Duration; +import java.util.UUID; + +/** + * This class demonstrates synchronous message processing with a standard Amazon SQS queue + * using the Amazon SQS Java Messaging Library. It shows how to receive messages from the queue + * using standard JMS (Java Message Service) interfaces, processing each message completely + * before moving to the next one. + */ +public class SyncMessageReceiver { + private static final Logger LOGGER = LoggerFactory.getLogger(SyncMessageReceiver.class); + public static final String QUEUE_NAME = "SQSJMSClientExampleQueue" + UUID.randomUUID(); + + public static void main(String[] args) { + try { + new Thread(SqsJmsExampleUtils.sendAMessageAsync(QUEUE_NAME, 10L, 1, SqsJmsExampleUtils.QUEUE_VISIBILITY_TIMEOUT)).start(); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } + try { + doReceiveMessageSync(); + SqsJmsExampleUtils.cleanUpExample(QUEUE_NAME, SqsJmsExampleUtils.QUEUE_VISIBILITY_TIMEOUT); + } catch (JMSException e) { + LOGGER.error(e.getMessage(), e); + } + } + + // snippet-start:[sqs-jms.java2.receive-message-sync] + /** + * This method receives messages from a standard Amazon SQS queue using the Amazon SQS Java + * Messaging Library. It creates a connection to the queue using JMS (Java Message Service), + * waits for messages to arrive, and processes them one at a time. The method handles all + * necessary setup and cleanup of messaging resources. + * + * @throws JMSException If there is a problem connecting to or receiving messages from the queue + */ + public static void doReceiveMessageSync() throws JMSException { + // Create a connection factory. + SQSConnectionFactory connectionFactory = new SQSConnectionFactory( + new ProviderConfiguration(), + SqsClient.create() + ); + + // Create a connection. + try (SQSConnection connection = connectionFactory.createConnection() ) { + + // Create the queue if needed. + SqsJmsExampleUtils.ensureQueueExists(connection, QUEUE_NAME, SqsJmsExampleUtils.QUEUE_VISIBILITY_TIMEOUT); + + // Create a session. + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(session.createQueue(QUEUE_NAME)); + + connection.start(); + + receiveMessages(consumer); + } // The connection closes automatically. This also closes the session. + LOGGER.info("Connection closed"); + } + + /** + * This method continuously checks for new messages from a standard Amazon SQS queue using + * the Amazon SQS Java Messaging Library. It waits up to 20 seconds for each message, processes + * it using JMS (Java Message Service), and confirms receipt. The method stops checking for + * messages after 20 seconds of no activity. + * + * @param consumer The JMS message consumer that receives messages from the queue + */ + private static void receiveMessages(MessageConsumer consumer) { + try { + while (true) { + LOGGER.info("Waiting for messages..."); + // Wait 1 minute for a message + Message message = consumer.receive(Duration.ofSeconds(20).toMillis()); + if (message == null) { + LOGGER.info("Shutting down after 20 seconds of silence."); + break; + } + SqsJmsExampleUtils.handleMessage(message); + message.acknowledge(); + LOGGER.info("Acknowledged message {}", message.getJMSMessageID()); + } + } catch (JMSException e) { + LOGGER.error("Error receiving from SQS: {}", e.getMessage(), e); + } + } + // snippet-end:[sqs-jms.java2.receive-message-sync] + +} diff --git a/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/stdqueue/SyncMessageReceiverClientAcknowledge.java b/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/stdqueue/SyncMessageReceiverClientAcknowledge.java new file mode 100644 index 00000000000..5695c8bf709 --- /dev/null +++ b/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/stdqueue/SyncMessageReceiverClientAcknowledge.java @@ -0,0 +1,144 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.sqs.jms.stdqueue; + +import com.amazon.sqs.javamessaging.ProviderConfiguration; +import com.amazon.sqs.javamessaging.SQSConnection; +import com.amazon.sqs.javamessaging.SQSConnectionFactory; +import com.example.sqs.jms.SqsJmsExampleUtils; +import jakarta.jms.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.services.sqs.SqsClient; + +import java.time.Duration; +import java.util.UUID; + +/** + * This class demonstrates manual message acknowledgment with a standard Amazon SQS queue + * using the Amazon SQS Java Messaging Library. It shows how to receive messages synchronously + * and explicitly confirm their processing using JMS (Java Message Service) client + * acknowledgment mode, giving the application full control over message completion. + */ +public class SyncMessageReceiverClientAcknowledge { + private static final Logger LOGGER = LoggerFactory.getLogger(SyncMessageReceiverClientAcknowledge.class); + public static final String QUEUE_NAME = "SQSJMSClientExampleQueue" + UUID.randomUUID(); + + // Visibility time-out for the queue. + private static final Long TIME_OUT_SECONDS = 5L; + private static final Long TIME_OUT_MILLIS = Duration.ofSeconds(TIME_OUT_SECONDS).toMillis(); + + public static void main(String[] args) { + try { + doReceiveMessagesSyncClientAcknowledge(); + SqsJmsExampleUtils.cleanUpExample(QUEUE_NAME, TIME_OUT_SECONDS); + } catch (JMSException e) { + LOGGER.error("JMS Exception occurred", e); + } + } + + // snippet-start:[sqs-jms.java2.receive-message-sync-client-ack] + /** + * This method demonstrates how message acknowledgment affects message processing in a standard + * Amazon SQS queue using the Amazon SQS Java Messaging Library. It sends messages to the queue, + * then shows how JMS (Java Message Service) client acknowledgment mode handles both explicit + * and implicit message confirmations, including how acknowledging one message can automatically + * acknowledge previous messages. + * + * @throws JMSException If there is a problem with the messaging operations + */ + public static void doReceiveMessagesSyncClientAcknowledge() throws JMSException { + // Create a connection factory. + SQSConnectionFactory connectionFactory = new SQSConnectionFactory( + new ProviderConfiguration(), + SqsClient.create() + ); + + // Create the connection in a try-with-resources statement so that it's closed automatically. + try (SQSConnection connection = connectionFactory.createConnection() ) { + + // Create the queue if needed. + SqsJmsExampleUtils.ensureQueueExists(connection, QUEUE_NAME, TIME_OUT_SECONDS); + + // Create a session with client acknowledge mode. + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + // Create a producer and consumer. + MessageProducer producer = session.createProducer(session.createQueue(QUEUE_NAME)); + MessageConsumer consumer = session.createConsumer(session.createQueue(QUEUE_NAME)); + + // Open the connection. + connection.start(); + + // Send two text messages. + sendMessage(producer, session, "Message 1"); + sendMessage(producer, session, "Message 2"); + + // Receive a message and don't acknowledge it. + receiveMessage(consumer, false); + + // Receive another message and acknowledge it. + receiveMessage(consumer, true); + + // Wait for the visibility time out, so that unacknowledged messages reappear in the queue, + LOGGER.info("Waiting for visibility timeout..."); + try { + Thread.sleep(TIME_OUT_MILLIS); + } catch (InterruptedException e) { + LOGGER.error("Interrupted while waiting for visibility timeout", e); + Thread.currentThread().interrupt(); + throw new RuntimeException("Processing interrupted", e); + } + + /* We will attempt to receive another message, but none will be available. This is because in + CLIENT_ACKNOWLEDGE mode, when we acknowledged the second message, all previous messages were + automatically acknowledged as well. Therefore, although we never directly acknowledged the first + message, it was implicitly acknowledged when we confirmed the second one. */ + receiveMessage(consumer, true); + } // The connection closes automatically. This also closes the session. + LOGGER.info("Connection closed."); + + } + + + /** + * Sends a text message using the specified JMS MessageProducer and Session. + * + * @param producer The JMS MessageProducer used to send the message + * @param session The JMS Session used to create the text message + * @param messageText The text content to be sent in the message + * @throws JMSException If there is an error creating or sending the message + */ + private static void sendMessage(MessageProducer producer, Session session, String messageText) throws JMSException { + // Create a text message and send it. + producer.send(session.createTextMessage(messageText)); + } + + /** + * Receives and processes a message from a JMS queue using the specified consumer. + * The method waits for a message until the configured timeout period is reached. + * If a message is received, it is logged and optionally acknowledged based on the + * acknowledge parameter. + * + * @param consumer The JMS MessageConsumer used to receive messages from the queue + * @param acknowledge Boolean flag indicating whether to acknowledge the message. + * If true, the message will be acknowledged after processing + * @throws JMSException If there is an error receiving, processing, or acknowledging the message + */ + private static void receiveMessage(MessageConsumer consumer, boolean acknowledge) throws JMSException { + // Receive a message. + Message message = consumer.receive(TIME_OUT_MILLIS); + + if (message == null) { + LOGGER.info("Queue is empty!"); + } else { + // Since this queue has only text messages, cast the message object and print the text. + LOGGER.info("Received: {} Acknowledged: {}", ((TextMessage) message).getText(), acknowledge); + + // Acknowledge the message if asked. + if (acknowledge) message.acknowledge(); + } + } + // snippet-end:[sqs-jms.java2.receive-message-sync-client-ack] +} diff --git a/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/stdqueue/SyncMessageReceiverUnorderedAcknowledge.java b/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/stdqueue/SyncMessageReceiverUnorderedAcknowledge.java new file mode 100644 index 00000000000..3ee743b3d08 --- /dev/null +++ b/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/stdqueue/SyncMessageReceiverUnorderedAcknowledge.java @@ -0,0 +1,140 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.sqs.jms.stdqueue; + +import com.amazon.sqs.javamessaging.ProviderConfiguration; +import com.amazon.sqs.javamessaging.SQSConnection; +import com.amazon.sqs.javamessaging.SQSConnectionFactory; +import com.amazon.sqs.javamessaging.SQSSession; +import com.example.sqs.jms.SqsJmsExampleUtils; +import jakarta.jms.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.services.sqs.SqsClient; + +import java.time.Duration; +import java.util.UUID; + +/** + * This class demonstrates independent message acknowledgment with a standard Amazon SQS queue + * using the Amazon SQS Java Messaging Library. It shows how to process messages using JMS + * (Java Message Service) with unordered acknowledgment mode, where each message must be + * confirmed separately regardless of when it was received, providing fine-grained control + * over message completion. + */ +public class SyncMessageReceiverUnorderedAcknowledge { + private static final Logger LOGGER = LoggerFactory.getLogger(SyncMessageReceiverUnorderedAcknowledge.class); + public static final String QUEUE_NAME = "SQSJMSClientExampleQueue" + UUID.randomUUID(); + + // Visibility time-out for the queue. + private static final Long TIME_OUT_SECONDS = 5L; + private static final Long TIME_OUT_MILLIS = Duration.ofSeconds(TIME_OUT_SECONDS).toMillis(); + + public static void main(String[] args) { + try { + doReceiveMessagesUnorderedAcknowledge(); + SqsJmsExampleUtils.cleanUpExample(QUEUE_NAME, TIME_OUT_SECONDS); + } catch (JMSException e) { + LOGGER.error(e.getMessage(), e); + } + } + + // snippet-start:[sqs-jms.java2.receive-message-sync-unordered-ack] + /** + * Demonstrates message acknowledgment behavior in UNORDERED_ACKNOWLEDGE mode with Amazon SQS JMS. + * In this mode, each message must be explicitly acknowledged regardless of receive order. + * Unacknowledged messages return to the queue after the visibility timeout expires, + * unlike CLIENT_ACKNOWLEDGE mode where acknowledging one message acknowledges all previous messages. + * + * @throws JMSException If a JMS-related error occurs during message operations + */ + public static void doReceiveMessagesUnorderedAcknowledge() throws JMSException { + // Create a connection factory. + SQSConnectionFactory connectionFactory = new SQSConnectionFactory( + new ProviderConfiguration(), + SqsClient.create() + ); + + // Create the connection in a try-with-resources statement so that it's closed automatically. + try( SQSConnection connection = connectionFactory.createConnection() ) { + + // Create the queue if needed. + SqsJmsExampleUtils.ensureQueueExists(connection, QUEUE_NAME, TIME_OUT_SECONDS); + + // Create a session with unordered acknowledge mode. + Session session = connection.createSession(false, SQSSession.UNORDERED_ACKNOWLEDGE); + + // Create the producer and consumer. + MessageProducer producer = session.createProducer(session.createQueue(QUEUE_NAME)); + MessageConsumer consumer = session.createConsumer(session.createQueue(QUEUE_NAME)); + + // Open a connection. + connection.start(); + + // Send two text messages. + sendMessage(producer, session, "Message 1"); + sendMessage(producer, session, "Message 2"); + + // Receive a message and don't acknowledge it. + receiveMessage(consumer, false); + + // Receive another message and acknowledge it. + receiveMessage(consumer, true); + + // Wait for the visibility time out, so that unacknowledged messages reappear in the queue. + LOGGER.info("Waiting for visibility timeout..."); + try { + Thread.sleep(TIME_OUT_MILLIS); + } catch (InterruptedException e) { + LOGGER.error("Interrupted while waiting for visibility timeout", e); + Thread.currentThread().interrupt(); + throw new RuntimeException("Processing interrupted", e); + } + + /* We will attempt to receive another message, and we'll get the first message again. This occurs + because in UNORDERED_ACKNOWLEDGE mode, each message requires its own separate acknowledgment. + Since we only acknowledged the second message, the first message remains in the queue for + redelivery. */ + receiveMessage(consumer, true); + + LOGGER.info("Connection closed."); + } // The connection closes automatically. This also closes the session. + } + + /** + * Sends a text message to an Amazon SQS queue using JMS. + * + * @param producer The JMS MessageProducer for the queue + * @param session The JMS Session for message creation + * @param messageText The message content + * @throws JMSException If message creation or sending fails + */ + private static void sendMessage(MessageProducer producer, Session session, String messageText) throws JMSException { + // Create a text message and send it. + producer.send(session.createTextMessage(messageText)); + } + /** + * Synchronously receives a message from an Amazon SQS queue using the JMS API + * with an acknowledgment parameter. + * + * @param consumer The JMS MessageConsumer for the queue + * @param acknowledge If true, acknowledges the message after receipt + * @throws JMSException If message reception or acknowledgment fails + */ + private static void receiveMessage(MessageConsumer consumer, boolean acknowledge) throws JMSException { + // Receive a message. + Message message = consumer.receive(TIME_OUT_MILLIS); + + if (message == null) { + LOGGER.info("Queue is empty!"); + } else { + // Since this queue has only text messages, cast the message object and print the text. + LOGGER.info("Received: {} Acknowledged: {}", ((TextMessage) message).getText(), acknowledge); + + // Acknowledge the message if asked. + if (acknowledge) message.acknowledge(); + } + } + // snippet-end:[sqs-jms.java2.receive-message-sync-unordered-ack] +} diff --git a/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/stdqueue/TextMessageSender.java b/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/stdqueue/TextMessageSender.java new file mode 100644 index 00000000000..4cd89dc497a --- /dev/null +++ b/javav2/example_code/sqs-jms/src/main/java/com/example/sqs/jms/stdqueue/TextMessageSender.java @@ -0,0 +1,113 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.sqs.jms.stdqueue; + +import com.amazon.sqs.javamessaging.ProviderConfiguration; +import com.amazon.sqs.javamessaging.SQSConnection; +import com.amazon.sqs.javamessaging.SQSConnectionFactory; +import com.example.sqs.jms.SqsJmsExampleUtils; +import jakarta.jms.JMSException; +import jakarta.jms.MessageProducer; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.services.sqs.SqsClient; + +import java.io.BufferedReader; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.util.UUID; + +/** + * This class demonstrates how to send text-based messages to a standard Amazon SQS queue + * using the Amazon SQS Java Messaging Library. It provides an interactive way to compose + * and send messages through JMS (Java Message Service), allowing users to type messages + * that are then delivered to the queue. + */ +public class TextMessageSender { + private static final Logger LOGGER = LoggerFactory.getLogger(TextMessageSender.class); + private static final String QUEUE_NAME = "SQSJMSClientExampleQueue" + UUID.randomUUID(); + + public static void main(String[] args) { + try { + doSendTextMessage(); + } catch (JMSException e) { + LOGGER.error("Failed to send message: {}", e.getMessage(), e); + } finally { + try { + SqsJmsExampleUtils.cleanUpExample(QUEUE_NAME, SqsJmsExampleUtils.QUEUE_VISIBILITY_TIMEOUT); + } catch (Exception e) { + LOGGER.error("Failed to cleanup resources: {}", e.getMessage(), e); + } + } + } + + // snippet-start:[sqs-jms.java2.send-text-message] + /** + * This method establishes a connection to a standard Amazon SQS queue using the Amazon SQS + * Java Messaging Library and sends text messages to it. It uses JMS (Java Message Service) API + * with automatic acknowledgment mode to ensure reliable message delivery, and automatically + * manages all messaging resources. + * + * @throws JMSException If there is a problem connecting to or sending messages to the queue + */ + public static void doSendTextMessage() throws JMSException { + // Create a connection factory. + SQSConnectionFactory connectionFactory = new SQSConnectionFactory( + new ProviderConfiguration(), + SqsClient.create() + ); + + // Create the connection in a try-with-resources statement so that it's closed automatically. + try (SQSConnection connection = connectionFactory.createConnection()) { + + // Create the queue if needed. + SqsJmsExampleUtils.ensureQueueExists(connection, QUEUE_NAME, SqsJmsExampleUtils.QUEUE_VISIBILITY_TIMEOUT); + + // Create a session that uses the JMS auto-acknowledge mode. + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = session.createProducer(session.createQueue(QUEUE_NAME)); + + createAndSendMessages(session, producer); + } // The connection closes automatically. This also closes the session. + LOGGER.info("Connection closed"); + } + + /** + * This method reads text input from the keyboard and sends each line as a separate message + * to a standard Amazon SQS queue using the Amazon SQS Java Messaging Library. It continues + * to accept input until the user enters an empty line, using JMS (Java Message Service) API to + * handle the message delivery. + * + * @param session The JMS session used to create messages + * @param producer The JMS message producer used to send messages to the queue + */ + private static void createAndSendMessages(Session session, MessageProducer producer) { + BufferedReader inputReader = new BufferedReader( + new InputStreamReader(System.in, Charset.defaultCharset())); + + try { + String input; + while (true) { + LOGGER.info("Enter message to send (leave empty to exit): "); + input = inputReader.readLine(); + if (input == null || input.isEmpty()) break; + + TextMessage message = session.createTextMessage(input); + producer.send(message); + LOGGER.info("Send message {}", message.getJMSMessageID()); + } + } catch (EOFException e) { + // Just return on EOF + } catch (IOException e) { + LOGGER.error("Failed reading input: {}", e.getMessage(), e); + } catch (JMSException e) { + LOGGER.error("Failed sending message: {}", e.getMessage(), e); + } + } + // snippet-end:[sqs-jms.java2.send-text-message] +} diff --git a/javav2/example_code/sqs-jms/src/main/resources/SpringExampleConfiguration.xml.txt b/javav2/example_code/sqs-jms/src/main/resources/SpringExampleConfiguration.xml.txt new file mode 100644 index 00000000000..7d05abca765 --- /dev/null +++ b/javav2/example_code/sqs-jms/src/main/resources/SpringExampleConfiguration.xml.txt @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/javav2/example_code/sqs-jms/src/main/resources/log4j2.xml b/javav2/example_code/sqs-jms/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..41b0f8963fc --- /dev/null +++ b/javav2/example_code/sqs-jms/src/main/resources/log4j2.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/javav2/example_code/sqs-jms/src/test/java/com/example/sqs/jms/basic/JmsSqsSyncStandardTest.java b/javav2/example_code/sqs-jms/src/test/java/com/example/sqs/jms/basic/JmsSqsSyncStandardTest.java new file mode 100644 index 00000000000..679453a26fb --- /dev/null +++ b/javav2/example_code/sqs-jms/src/test/java/com/example/sqs/jms/basic/JmsSqsSyncStandardTest.java @@ -0,0 +1,149 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.sqs.jms.basic; + +import com.amazon.sqs.javamessaging.AmazonSQSMessagingClientWrapper; +import com.amazon.sqs.javamessaging.ProviderConfiguration; +import com.amazon.sqs.javamessaging.SQSConnection; +import com.amazon.sqs.javamessaging.SQSConnectionFactory; +import jakarta.jms.JMSException; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageProducer; +import jakarta.jms.Queue; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.services.sqs.SqsClient; + +import java.util.UUID; + +class JmsSqsSyncStandardTest { + private final String QUEUE_NAME = "MyQueueTst" + UUID.randomUUID(); + private SQSConnection connection; + + @BeforeEach + void setUp() { + try { + SQSConnectionFactory connectionFactory = new SQSConnectionFactory( + new ProviderConfiguration(), + SqsClient.create() + ); + connection = connectionFactory.createConnection(); + AmazonSQSMessagingClientWrapper client = connection.getWrappedAmazonSQSClient(); + // Create an SQS queue named 'MyQueue', if it doesn't already exist. + if (!client.queueExists(QUEUE_NAME)) { + client.createQueue(QUEUE_NAME); + } + } catch (JMSException e) { + throw new RuntimeException(e); + } + } + @AfterEach + void tearDown() { + try { + SqsClient sqsClient = connection.getWrappedAmazonSQSClient().getAmazonSQSClient(); + String queueUrl = connection.getWrappedAmazonSQSClient().getQueueUrl(QUEUE_NAME).queueUrl(); + connection.close(); + if (queueUrl != null){ + sqsClient.deleteQueue(b -> b.queueUrl(queueUrl)); + } + } catch (JMSException e) { + throw new RuntimeException(e); + } + } + + @Test + void autoAckAsyncTest() { + try { + Session session = JmsSqsSyncStandard.createAutoAcknowledgeSession(connection); + Queue queue = session.createQueue(QUEUE_NAME); + MessageProducer producer = session.createProducer(queue); + TextMessage message = session.createTextMessage("Hello World!"); + producer.send(message); + JmsSqsSyncStandard.receiveMessageAutoAckAsync(connection, session, queue); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + MessageConsumer consumer = session.createConsumer(queue); + connection.start(); + Message reReceivedMessage = consumer.receive(1000); + Assertions.assertNull(reReceivedMessage); + } catch (JMSException e) { + throw new RuntimeException(e); + } + } + @Test + void autoAckSyncTest() { + try { + Session session = JmsSqsSyncStandard.createAutoAcknowledgeSession(connection); + Queue queue = session.createQueue(QUEUE_NAME); + MessageProducer producer = session.createProducer(queue); + TextMessage message = session.createTextMessage("Hello World!"); + producer.send(message); + JmsSqsSyncStandard.receiveMessageAutoAckAsync(connection, session, queue); + + MessageConsumer consumer = session.createConsumer(queue); + connection.start(); + Message reReceivedMessage = consumer.receive(1000); + Assertions.assertNull(reReceivedMessage); + + } catch (JMSException e) { + throw new RuntimeException(e); + } + } + @Test + @Tag("IntegrationTest") + void clientAckSyncTest() { + try { + Session session = JmsSqsSyncStandard.createClientAcknowledgeSession(connection); + Queue queue = session.createQueue(QUEUE_NAME); + MessageProducer producer = session.createProducer(queue); + TextMessage message = session.createTextMessage("Hello World!"); + producer.send(message); + JmsSqsSyncStandard.receiveMessageExplicitAckSync(connection, session, queue); + + MessageConsumer consumer = session.createConsumer(queue); + connection.start(); + Message reReceivedMessage = consumer.receive(1000); + Assertions.assertNull(reReceivedMessage); + + } catch (JMSException e) { + throw new RuntimeException(e); + } + } + + @Test + @Tag("IntegrationTest") + void unorderedAckSyncTest() { + try { + Session session = JmsSqsSyncStandard.createUnorderedAcknowledgeSession(connection); + Queue queue = session.createQueue(QUEUE_NAME); + MessageProducer producer = session.createProducer(queue); + TextMessage message = session.createTextMessage("Hello World!"); + producer.send(message); + JmsSqsSyncStandard.receiveMessageExplicitAckSync(connection, session, queue); + + MessageConsumer consumer = session.createConsumer(queue); + connection.start(); + Message reReceivedMessage = consumer.receive(1000); + Assertions.assertNull(reReceivedMessage); + + } catch (JMSException e) { + throw new RuntimeException(e); + } + } + + @Test + @Tag("IntegrationTest") + void fifoQueueWorks() { + Assertions.assertDoesNotThrow(() -> JmsSqsSyncFifo.main(null)); + } +} \ No newline at end of file diff --git a/javav2/example_code/sqs-jms/src/test/java/com/example/sqs/jms/stdqueue/AsyncMessageReceiverTest.java b/javav2/example_code/sqs-jms/src/test/java/com/example/sqs/jms/stdqueue/AsyncMessageReceiverTest.java new file mode 100644 index 00000000000..0def734d3a4 --- /dev/null +++ b/javav2/example_code/sqs-jms/src/test/java/com/example/sqs/jms/stdqueue/AsyncMessageReceiverTest.java @@ -0,0 +1,47 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.sqs.jms.stdqueue; + +import com.example.sqs.jms.SqsJmsExampleUtils; +import jakarta.jms.JMSException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.services.sqs.SqsClient; +import software.amazon.awssdk.services.sqs.model.ReceiveMessageResponse; + +class AsyncMessageReceiverTest { +private static final Logger LOGGER = LoggerFactory.getLogger(AsyncMessageReceiverTest.class); + @AfterEach + void tearDown() throws JMSException { + SqsJmsExampleUtils.cleanUpExample(AsyncMessageReceiver.QUEUE_NAME, SqsJmsExampleUtils.QUEUE_VISIBILITY_TIMEOUT ); + } + + @Test + @Tag("IntegrationTest") + void doReceiveMessageAsyncTest() { + try { + new Thread(SqsJmsExampleUtils.sendAMessageAsync(AsyncMessageReceiver.QUEUE_NAME, 3L, 5, SqsJmsExampleUtils.QUEUE_VISIBILITY_TIMEOUT)).start(); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } + try { + AsyncMessageReceiver.doReceiveMessageAsync(); + } catch (JMSException e) { + LOGGER.error(e.getMessage(), e); + } + + // Use plain SQS test to make sure there are no messages in the queue. + try (SqsClient sqsClient = SqsClient.create()) { + ReceiveMessageResponse response = sqsClient.receiveMessage(b -> b.queueUrl(sqsClient + .getQueueUrl(builder -> builder + .queueName(AsyncMessageReceiver.QUEUE_NAME)).queueUrl())); + + Assertions.assertFalse(response.hasMessages()); + } + } +} \ No newline at end of file diff --git a/javav2/example_code/sqs-jms/src/test/java/com/example/sqs/jms/stdqueue/SyncMessageReceiverClientAckTest.java b/javav2/example_code/sqs-jms/src/test/java/com/example/sqs/jms/stdqueue/SyncMessageReceiverClientAckTest.java new file mode 100644 index 00000000000..0f343663f9e --- /dev/null +++ b/javav2/example_code/sqs-jms/src/test/java/com/example/sqs/jms/stdqueue/SyncMessageReceiverClientAckTest.java @@ -0,0 +1,43 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.sqs.jms.stdqueue; + +import com.example.sqs.jms.SqsJmsExampleUtils; +import jakarta.jms.JMSException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.services.sqs.SqsClient; +import software.amazon.awssdk.services.sqs.model.ReceiveMessageResponse; + +class SyncMessageReceiverClientAckTest { + private static final Logger LOGGER = LoggerFactory.getLogger(SyncMessageReceiverClientAckTest.class); + + @AfterEach + void tearDown() throws JMSException { + SqsJmsExampleUtils.cleanUpExample(SyncMessageReceiverClientAcknowledge.QUEUE_NAME, SqsJmsExampleUtils.QUEUE_VISIBILITY_TIMEOUT ); + } + + @Test + @Tag("IntegrationTest") + void doReceiveMessagesSyncClientAcknowledgeTest() { + try { + SyncMessageReceiverClientAcknowledge.doReceiveMessagesSyncClientAcknowledge(); + } catch (JMSException e) { + LOGGER.error(e.getMessage(), e); + } + + // Use plain SQS test to make sure there are no messages in the queue. + try (SqsClient sqsClient = SqsClient.create()) { + ReceiveMessageResponse response = sqsClient.receiveMessage(b -> b.queueUrl(sqsClient + .getQueueUrl(builder -> builder + .queueName(SyncMessageReceiverClientAcknowledge.QUEUE_NAME)).queueUrl())); + + Assertions.assertFalse(response.hasMessages()); + } + } +} \ No newline at end of file diff --git a/javav2/example_code/sqs-jms/src/test/java/com/example/sqs/jms/stdqueue/SyncMessageReceiverTest.java b/javav2/example_code/sqs-jms/src/test/java/com/example/sqs/jms/stdqueue/SyncMessageReceiverTest.java new file mode 100644 index 00000000000..5d0aa7825cc --- /dev/null +++ b/javav2/example_code/sqs-jms/src/test/java/com/example/sqs/jms/stdqueue/SyncMessageReceiverTest.java @@ -0,0 +1,47 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.sqs.jms.stdqueue; + +import com.example.sqs.jms.SqsJmsExampleUtils; +import jakarta.jms.JMSException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.services.sqs.SqsClient; +import software.amazon.awssdk.services.sqs.model.ReceiveMessageResponse; + +class SyncMessageReceiverTest { +private static final Logger LOGGER = LoggerFactory.getLogger(SyncMessageReceiverTest.class); + @AfterEach + void tearDown() throws JMSException { + SqsJmsExampleUtils.cleanUpExample(SyncMessageReceiver.QUEUE_NAME, SqsJmsExampleUtils.QUEUE_VISIBILITY_TIMEOUT ); + } + + @Test + @Tag("IntegrationTest") + void doReceiveMessageSyncTest() { + try { + new Thread(SqsJmsExampleUtils.sendAMessageAsync(SyncMessageReceiver.QUEUE_NAME, 10L, 1, SqsJmsExampleUtils.QUEUE_VISIBILITY_TIMEOUT)).start(); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } + try { + SyncMessageReceiver.doReceiveMessageSync(); + } catch (JMSException e) { + LOGGER.error(e.getMessage(), e); + } + + // Use plain SQS test to make sure there are no messages in the queue. + try (SqsClient sqsClient = SqsClient.create()) { + ReceiveMessageResponse response = sqsClient.receiveMessage(b -> b.queueUrl(sqsClient + .getQueueUrl(builder -> builder + .queueName(SyncMessageReceiver.QUEUE_NAME)).queueUrl())); + + Assertions.assertFalse(response.hasMessages()); + } + } +} \ No newline at end of file diff --git a/javav2/example_code/sqs-jms/src/test/java/com/example/sqs/jms/stdqueue/SyncMessageReceiverUnorderedAckTest.java b/javav2/example_code/sqs-jms/src/test/java/com/example/sqs/jms/stdqueue/SyncMessageReceiverUnorderedAckTest.java new file mode 100644 index 00000000000..7e4e217669c --- /dev/null +++ b/javav2/example_code/sqs-jms/src/test/java/com/example/sqs/jms/stdqueue/SyncMessageReceiverUnorderedAckTest.java @@ -0,0 +1,44 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.sqs.jms.stdqueue; + +import com.example.sqs.jms.SqsJmsExampleUtils; +import jakarta.jms.JMSException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.services.sqs.SqsClient; +import software.amazon.awssdk.services.sqs.model.ReceiveMessageResponse; + +class SyncMessageReceiverUnorderedAckTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(SyncMessageReceiverUnorderedAckTest.class); + + @AfterEach + void tearDown() throws JMSException { + SqsJmsExampleUtils.cleanUpExample(SyncMessageReceiverUnorderedAcknowledge.QUEUE_NAME, SqsJmsExampleUtils.QUEUE_VISIBILITY_TIMEOUT ); + } + + @Test + @Tag("IntegrationTest") + void doReceiveMessagesSyncUnorderedAcknowledgeTest() { + try { + SyncMessageReceiverUnorderedAcknowledge.doReceiveMessagesUnorderedAcknowledge(); + } catch (JMSException e) { + LOGGER.error(e.getMessage(), e); + } + + // Use plain SQS test to make sure there are no messages in the queue. + try (SqsClient sqsClient = SqsClient.create()) { + ReceiveMessageResponse response = sqsClient.receiveMessage(b -> b.queueUrl(sqsClient + .getQueueUrl(builder -> builder + .queueName(SyncMessageReceiverUnorderedAcknowledge.QUEUE_NAME)).queueUrl())); + + Assertions.assertFalse(response.hasMessages()); + } + } +} \ No newline at end of file diff --git a/javav2/example_code/sqs-jms/src/test/java/com/example/sqs/jms/stdqueue/TextMessageSenderTest.java b/javav2/example_code/sqs-jms/src/test/java/com/example/sqs/jms/stdqueue/TextMessageSenderTest.java new file mode 100644 index 00000000000..e6b47326c05 --- /dev/null +++ b/javav2/example_code/sqs-jms/src/test/java/com/example/sqs/jms/stdqueue/TextMessageSenderTest.java @@ -0,0 +1,17 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.sqs.jms.stdqueue; + +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class TextMessageSenderTest { + private static final Logger LOGGER = LoggerFactory.getLogger(TextMessageSenderTest.class); + @Test + void doSendTextMessageTest() { + // The TextMessageSender.doSendTextMessage() can't be tested with an automated test because it requires user input. + } + +} \ No newline at end of file diff --git a/javav2/example_code/sqs/README.md b/javav2/example_code/sqs/README.md index 99a931137c8..194236086be 100644 --- a/javav2/example_code/sqs/README.md +++ b/javav2/example_code/sqs/README.md @@ -56,6 +56,7 @@ functions within the same service. - [Create and publish to a FIFO topic](../sns/src/main/java/com/example/sns/PriceUpdateExample.java) - [Process S3 event notifications](../s3/src/main/java/com/example/s3/ProcessS3EventNotification.java) - [Publish messages to queues](../../usecases/topics_and_queues/src/main/java/com/example/sns/SNSWorkflow.java) +- [Use the Amazon SQS Java Messaging Library to work with the JMS interface](../sqs-jms/src/main/java/com/example/sqs/jms/stdqueue/TextMessageSender.java) - [Work with queue tags](src/main/java/com/example/sqs/TagExamples.java) @@ -116,9 +117,21 @@ This example shows you how to do the following: +#### Use the Amazon SQS Java Messaging Library to work with the JMS interface + +This example shows you how to use the Amazon SQS Java Messaging Library to work with the JMS interface. + + + + + + + + + #### Work with queue tags -This example shows you how to perform tagging operation with Amazon SQS +This example shows you how to perform tagging operation with Amazon SQS. diff --git a/php/applications/photo_asset_manager/bootstrap.zip b/php/applications/photo_asset_manager/bootstrap.zip deleted file mode 100644 index 69cebcb07a4..00000000000 Binary files a/php/applications/photo_asset_manager/bootstrap.zip and /dev/null differ