

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 搭配 Amazon SQS 使用 JMS
<a name="sqs-java-message-service-jms-client"></a>

Amazon SQS Java 訊息程式庫是適用於 Amazon SQS 的 Java 訊息服務 (JMS) 界面，可讓您在已經使用 JMS 的應用程式中充分運用 Amazon SQS。此界面可讓您盡可能不變更程式碼就能使用 Amazon SQS 做為 JMS 的供應者。搭配 適用於 Java 的 AWS SDK，Amazon SQS Java 訊息程式庫可建立 JMS 連線和工作階段，以及傳送和接收 Amazon SQS 佇列訊息的生產者和消費者。

此程式庫支援符合 [JMS 1.1 規格](http://docs.oracle.com/javaee/6/api/javax/jms/package-summary.html)的佇列訊息傳送和接收 (JMS 點對點模式)。此程式庫支援同步將文字、位元組、物件訊息傳送至 Amazon SQS 佇列。此程式庫也支援同步或非同步接收物件。

如需支援 JMS 1.1 規格的 Amazon SQS Java 訊息程式庫功能資訊，請參閱 [Amazon SQS 支援的 JMS 1.1 實作](supported-implementations.md) 以及 [Amazon SQS 常見問答集](https://aws.amazon.com/sqs/faqs/)。

# 使用 JMS 和 Amazon SQS 的先決條件
<a name="prerequisites"></a>

開始之前，您必須準備好以下事項：
+ **適用於 Java 的開發套件**

  有兩種方式可將適用於 Java 的開發套件納入您的專案：
  + 下載並安裝適用於 Java 的開發套件。
  + 使用 Maven 以獲得 Amazon SQS Java 訊息程式庫。
**注意**  
適用於 Java 的開發套件會為相依性包含在內。  
[適用於 Java 的開發套件](https://aws.amazon.com/sdkforjava/)和適用於 Java 的 Amazon SQS 擴充用戶端程式庫需要 J2SE 開發套件 8.0 或更新版本。

    如需關於下載適用於 Java 的開發套件的資訊，請參閱[適用於 Java 的開發套件](https://aws.amazon.com/sdkforjava/)。
+ **Amazon SQS Java 訊息程式庫** 

  若您不使用 Maven，您必須將 `amazon-sqs-java-messaging-lib.jar` 套件新增至 Java 類別路徑。如需下載程式庫的資訊，請參閱 [Amazon SQS Java 訊息程式庫](https://github.com/awslabs/amazon-sqs-java-messaging-lib)。
**注意**  
Amazon SQS Java 訊息程式庫包含對 [Maven](http://maven.apache.org/) 及 [Spring Framework](http://projects.spring.io/spring-framework/) 的支援。  
如需使用 Maven、Spring Framework、Amazon SQS Java 訊息程式庫的範本程式碼，請參閱 [搭配 Amazon SQS 標準佇列使用 JMS 的工作 Java 範例](sqs-jms-code-examples.md)。  

  ```
  <dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>amazon-sqs-java-messaging-lib</artifactId>
    <version>1.0.4</version>
    <type>jar</type>
  </dependency>
  ```
+ **Amazon SQS 佇列**

  使用 Amazon SQS、`CreateQueue`API AWS 管理主控台 或包含在 Amazon SQS Java Messaging Library 中的包裝 Amazon SQS 用戶端來建立佇列。
  + 如需使用 AWS 管理主控台 或 `CreateQueue` API 以 Amazon SQS 建立佇列的詳細資訊，請參閱[建立佇列](creating-sqs-standard-queues.md#step-create-standard-queue)。
  + 如需使用 Amazon SQS Java 訊息程式庫的詳細資訊，請參閱 [使用 Amazon SQS Java Messaging Library](getting-started.md)。

# 使用 Amazon SQS Java Messaging Library
<a name="getting-started"></a>

若要開始使用 Java 訊息服務 (JMS) 搭配 Amazon SQS，請使用本節中的程式碼範例。以下章節會示範如何建立 JMS 連線和工作階段，以及如何傳送和接收訊息。

包含在 Amazon SQS Java 訊息程式庫的包裝 Amazon SQS 用戶端物件會檢查 Amazon SQS 佇列是否存在。如果佇列不存在，用戶端便會建立佇列。

## 建立 JMS 連線
<a name="creating-connection"></a>

開始之前，請參閱 中的先決條件[使用 JMS 和 Amazon SQS 的先決條件](prerequisites.md)。

1. 請建立連現工廠並對工廠呼叫 `createConnection` 方法。

   ```
   // Create a new connection factory with all defaults (credentials and region) set automatically
   SQSConnectionFactory connectionFactory = new SQSConnectionFactory(
           new ProviderConfiguration(),
           AmazonSQSClientBuilder.defaultClient()
           );
    
   // Create the connection.
   SQSConnection connection = connectionFactory.createConnection();
   ```

   `SQSConnection` 類別會將 `javax.jms.Connection` 延伸。搭配 JMS 標準連線方法，`SQSConnection` 會提供額外的方法，例如 `getAmazonSQSClient` 和 `getWrappedAmazonSQSClient`。兩種方法皆能執行不包含在 JMS 規格內的管理操作，例如建立新佇列。不過，`getWrappedAmazonSQSClient` 方法還可提供目前連線使用的 Amazon SQS 用戶端的包裝版本。包裝函式會將每個例外狀況從用戶端的轉換為 `JMSException`，讓如此可更輕鬆地由預期 `JMSException` 事件的既有程式碼使用。

1. 您可以使用 `getAmazonSQSClient` 及 `getWrappedAmazonSQSClient` 傳回的用戶端物件來執行未包含在 JMS 規格內的管理操作 (例如建立 Amazon SQS 佇列)。

    若有會預期 JMS 例外狀況出現的既有程式碼，則應使用 `getWrappedAmazonSQSClient`：
   + 若您使用 `getWrappedAmazonSQSClient`，傳回的用戶端物件會將所有例外狀況轉換為 JMS 例外狀況。
   + 若您使用 `getAmazonSQSClient`，例外狀況全為 Amazon SQS 例外狀況。

## 建立 Amazon SQS 佇列
<a name="creating-queue"></a>

包裝用戶端物件會檢查 Amazon SQS 佇列是否存在。

如果佇列不存在，用戶端便會建立佇列。如果佇列存在，該函數不會傳回任何內容。如需詳細資訊，請參閱視需要建立佇列章節的 [TextMessageSender.java](sqs-jms-code-examples.md#example-sender) 範例。

### 建立標準佇列
<a name="creating-queue-standard"></a>

```
// Get the wrapped client
AmazonSQSMessagingClientWrapper client = connection.getWrappedAmazonSQSClient();
 
// Create an SQS queue named MyQueue, if it doesn't already exist
if (!client.queueExists("MyQueue")) {
    client.createQueue("MyQueue");
}
```

### 若要建立 FIFO 佇列
<a name="creating-queue-FIFO"></a>

```
// Get the wrapped client
AmazonSQSMessagingClientWrapper client = connection.getWrappedAmazonSQSClient();

// Create an Amazon SQS FIFO queue named MyQueue.fifo, if it doesn't already exist
if (!client.queueExists("MyQueue.fifo")) {
    Map<String, String> attributes = new HashMap<String, String>();
    attributes.put("FifoQueue", "true");
    attributes.put("ContentBasedDeduplication", "true");
    client.createQueue(new CreateQueueRequest().withQueueName("MyQueue.fifo").withAttributes(attributes));
}
```

**注意**  
FIFO 佇列名稱結尾必須是 `.fifo` 尾碼。  
如需 `ContentBasedDeduplication` 屬性的相關資訊，請參閱[Amazon SQS 中的精確一次處理](FIFO-queues-exactly-once-processing.md)。

## 同步傳送訊息
<a name="send-messages-synchronously"></a>

1. 當連線和底層的 Amazon SQS 佇列準備好之時，請以 `AUTO_ACKNOWLEDGE` 模式建立非交易的 JMS 工作階段。

   ```
   // Create the nontransacted session with AUTO_ACKNOWLEDGE mode
   Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
   ```

1. 若要傳送文字訊息到佇列，請建立 JMS 佇列身分和訊息生產者。

   ```
   // Create a queue identity and specify the queue name to the session
   Queue queue = session.createQueue("MyQueue");
    
   // Create a producer for the 'MyQueue'
   MessageProducer producer = session.createProducer(queue);
   ```

1. 請建立文字訊息，並傳送到佇列。
   + 若要傳送訊息到標準佇列，則無需設定任何額外參數。

     ```
     // Create the text message
     TextMessage message = session.createTextMessage("Hello World!");
      
     // Send the message
     producer.send(message);
     System.out.println("JMS Message " + message.getJMSMessageID());
     ```
   + 若要傳送訊息到 FIFO 佇列，則必須設定訊息群組 ID。您也可以設定訊息重複資料刪除 ID。如需詳細資訊，請參閱 [Amazon SQS FIFO 佇列金鑰術語](FIFO-key-terms.md)。

     ```
     // Create the 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
     // message.setStringProperty("JMS_SQS_DeduplicationId", "hello");
     // Here, it's not needed because content-based deduplication is enabled for the queue
     
     // Send the message
     producer.send(message);
     System.out.println("JMS Message " + message.getJMSMessageID());
     System.out.println("JMS Message Sequence Number " + message.getStringProperty("JMS_SQS_SequenceNumber"));
     ```

## 同步接收訊息
<a name="receive-messages-synchronously"></a>

1. 若要接收訊息，請建立相同佇列的消費者並呼叫 `start` 方法。

   您可以隨時在連線上呼叫 `start` 方法。不過，消費者在您呼叫前不會接收訊息。

   ```
   // Create a consumer for the 'MyQueue'
   MessageConsumer consumer = session.createConsumer(queue);
   // Start receiving incoming messages
   connection.start();
   ```

1. 請在消費者上呼叫 `receive` 方法呼叫，將逾時設定為 1 秒，然後將接收訊息的內容列印出來。
   + 從標準佇列接收訊息後，即可存取訊息內容。

     ```
     // Receive a message from 'MyQueue' and wait up to 1 second
     Message receivedMessage = consumer.receive(1000);
      
     // Cast the received message as TextMessage and display the text
     if (receivedMessage != null) {
         System.out.println("Received: " + ((TextMessage) receivedMessage).getText());
     }
     ```
   + 從 FIFO 佇列接收訊息後，即可存取訊息的內容和其他 FIFO 特定的訊息屬性，例如訊息群組 ID、訊息重複資料刪除 ID 和序號。如需詳細資訊，請參閱 [Amazon SQS FIFO 佇列金鑰術語](FIFO-key-terms.md)。

     ```
     // Receive a message from 'MyQueue' and wait up to 1 second
     Message receivedMessage = consumer.receive(1000);
     
     // Cast the received message as TextMessage and display the text
     if (receivedMessage != null) {
         System.out.println("Received: " + ((TextMessage) receivedMessage).getText());
         System.out.println("Group id: " + receivedMessage.getStringProperty("JMSXGroupID"));
         System.out.println("Message deduplication id: " + receivedMessage.getStringProperty("JMS_SQS_DeduplicationId"));
         System.out.println("Message sequence number: " + receivedMessage.getStringProperty("JMS_SQS_SequenceNumber"));
     }
     ```

1. 關閉連線和工作階段。

   ```
   // Close the connection (and the session).
   connection.close();
   ```

輸出結果類似如下：

```
JMS Message ID:8example-588b-44e5-bbcf-d816example2
Received: Hello World!
```

**注意**  
您可以使用 Spring Framework 來初始化這些物件。  
如需其他資訊，請參閱 `SpringExampleConfiguration.xml`、`SpringExample.java` 和 `ExampleConfiguration.java` 節的 `ExampleCommon.java`、[搭配 Amazon SQS 標準佇列使用 JMS 的工作 Java 範例](sqs-jms-code-examples.md) 的其他說明類別。

如需傳送和接收物件的完整範例，請參閱 [TextMessageSender.java](sqs-jms-code-examples.md#example-sender) 和 [SyncMessageReceiver.java](sqs-jms-code-examples.md#example-synchronous-message-receiver)。

## 異步接收訊息
<a name="receive-messages-asynchronously"></a>

在 [使用 Amazon SQS Java Messaging Library](#getting-started) 的範例中，訊息會傳送到 `MyQueue` 並同步接收。

以下範例顯示的是如何透過接聽程式異步接收訊息。

1. 實作 `MessageListener` 介面。

   ```
   class MyListener implements MessageListener {
    
       @Override
       public void onMessage(Message message) {
           try {
               // Cast the received message as TextMessage and print the text to screen.
               System.out.println("Received: " + ((TextMessage) message).getText());
           } catch (JMSException e) {
               e.printStackTrace();
           }
       }
   }
   ```

   收到訊息時，即會呼叫 `MessageListener` 介面的 `onMessage` 方法。在此接聽程式的實作中，會將儲存在訊息中的文字列印出來。

1. 消費者端不會明確地呼叫 `receive` 方法，而是將消費者的訊息接聽程式設定為 `MyListener` 實作的執行個體。主執行緒會等待一秒。

   ```
   // Create a consumer for the 'MyQueue'.
   MessageConsumer consumer = session.createConsumer(queue);
    
   // Instantiate and set the message listener for the consumer.
   consumer.setMessageListener(new MyListener());
    
   // Start receiving incoming messages.
   connection.start();
    
   // Wait for 1 second. The listener onMessage() method is invoked when a message is received.
   Thread.sleep(1000);
   ```

接下來的步驟與 [使用 Amazon SQS Java Messaging Library](#getting-started) 範例相同。如需異步消費者的完整資訊，請參閱 `AsyncMessageReceiver.java` 的 [搭配 Amazon SQS 標準佇列使用 JMS 的工作 Java 範例](sqs-jms-code-examples.md)。

此範例的輸出結果類似如下：

```
JMS Message ID:8example-588b-44e5-bbcf-d816example2
Received: Hello World!
```

## 使用用戶端認可模式
<a name="using-client-acknowledge-mode"></a>

[使用 Amazon SQS Java Messaging Library](#getting-started) 中的範例使用 `AUTO_ACKNOWLEDGE` 模式，所有接收到的訊息會自動獲得認可 (因此會從底層的 Amazon SQS 佇列刪除)。

1. 若要明確在處理訊息後予以認可，則必須建立使用 `CLIENT_ACKNOWLEDGE` 模式的工作階段。

   ```
   // Create the non-transacted session with CLIENT_ACKNOWLEDGE mode.
   Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
   ```

1. 收到訊息後，會顯示訊息再明確予以認可。

   ```
   // Cast the received message as TextMessage and print the text to screen. Also acknowledge the message.
   if (receivedMessage != null) {
       System.out.println("Received: " + ((TextMessage) receivedMessage).getText());
       receivedMessage.acknowledge();
       System.out.println("Acknowledged: " + message.getJMSMessageID());
   }
   ```
**注意**  
在此模式中，當訊息受到認可，所有在此之前收到的訊息也會預設為認可。舉例而言，若收到 10 則訊息，而只有第 10 則訊息受到認可 (按訊息接收順序)，則之前的九則訊息也會受到認可。

接下來的步驟與 [使用 Amazon SQS Java Messaging Library](#getting-started) 範例相同。如需異步消費者用戶端認可模式的完整範例，請參閱 `SyncMessageReceiverClientAcknowledge.java` 的 [搭配 Amazon SQS 標準佇列使用 JMS 的工作 Java 範例](sqs-jms-code-examples.md)。

此範例的輸出結果類似如下：

```
JMS Message ID:4example-aa0e-403f-b6df-5e02example5
Received: Hello World!
Acknowledged: ID:4example-aa0e-403f-b6df-5e02example5
```

## 使用無順序認可模式
<a name="using-unordered-acknowledge-mode"></a>

當使用 `CLIENT_ACKNOWLEDGE` 模式時，受到明確認可的訊息之前所有接收到的訊息均會自動受到認可。如需詳細資訊，請參閱 [使用用戶端認可模式](#using-client-acknowledge-mode)。

Amazon SQS Java 訊息程式庫提供了另一種認可模式。使用 `UNORDERED_ACKNOWLEDGE` 模式時，所有接收的訊息必須明確受到用戶端個別認可，無論接收順序。若要這樣做，請建立 `UNORDERED_ACKNOWLEDGE` 模式的工作階段。

```
// Create the non-transacted session with UNORDERED_ACKNOWLEDGE mode.
Session session = connection.createSession(false, SQSSession.UNORDERED_ACKNOWLEDGE);
```

其他步驟與 [使用用戶端認可模式](#using-client-acknowledge-mode) 範例相同。如需同步消費者 `UNORDERED_ACKNOWLEDGE` 模式的完整資訊，請參閱 `SyncMessageReceiverUnorderedAcknowledge.java`。

此範例的輸出結果類似如下：

```
JMS Message ID:dexample-73ad-4adb-bc6c-4357example7
Received: Hello World!
Acknowledged: ID:dexample-73ad-4adb-bc6c-4357example7
```

# 將 Java Message Service 與其他 Amazon SQS 用戶端搭配使用
<a name="sqs-jms-client-with-sqs-clients"></a>

搭配 AWS SDK 使用 Amazon SQS Java Message Service (JMS) 用戶端會將 Amazon SQS 訊息大小限制為 256 KB。不過，您可以使用任何 Amazon SQS 用戶端建立 JMS 提供者。例如，您可以使用 JMS Client 搭配適用於 Java 的 Amazon SQS 擴充用戶端程式庫來傳送 Amazon SQS 訊息，其中包含對 Amazon S3 中的訊息承載 (最多 2 GB) 的參考。如需詳細資訊，請參閱[使用 Java 和 Amazon S3 管理大型 Amazon SQS 訊息 Amazon S3](sqs-s3-messages.md)。

下列 Java 程式碼範例會為擴充用戶端程式庫建立 JMS 提供者。

在測試此範例[使用 JMS 和 Amazon SQS 的先決條件](prerequisites.md)之前，請參閱 中的先決條件。

```
AmazonS3 s3 = new AmazonS3Client(credentials);
Region s3Region = Region.getRegion(Regions.US_WEST_2);
s3.setRegion(s3Region);
 
// Set the Amazon S3 bucket name, and set a lifecycle rule on the bucket to
// permanently delete objects a certain number of days after each object's creation date.
// Next, create the bucket, and enable message objects to be stored in the bucket.
BucketLifecycleConfiguration.Rule expirationRule = new BucketLifecycleConfiguration.Rule();
expirationRule.withExpirationInDays(14).withStatus("Enabled");
BucketLifecycleConfiguration lifecycleConfig = new BucketLifecycleConfiguration().withRules(expirationRule);
 
s3.createBucket(s3BucketName);
s3.setBucketLifecycleConfiguration(s3BucketName, lifecycleConfig);
System.out.println("Bucket created and configured.");

// Set the SQS extended client configuration with large payload support enabled.
ExtendedClientConfiguration extendedClientConfig = new ExtendedClientConfiguration()
    .withLargePayloadSupportEnabled(s3, s3BucketName);
 
AmazonSQS sqsExtended = new AmazonSQSExtendedClient(new AmazonSQSClient(credentials), extendedClientConfig);
Region sqsRegion = Region.getRegion(Regions.US_WEST_2);
sqsExtended.setRegion(sqsRegion);
```

以下 Java 範本程式碼會建立連線工廠：

```
// Create the connection factory using the environment variable credential provider.
// Pass the configured Amazon SQS Extended Client to the JMS connection factory.
SQSConnectionFactory connectionFactory = new SQSConnectionFactory(
        new ProviderConfiguration(),
        sqsExtended
        );
 
// Create the connection.
SQSConnection connection = connectionFactory.createConnection();
```

# 搭配 Amazon SQS 標準佇列使用 JMS 的工作 Java 範例
<a name="sqs-jms-code-examples"></a>

下列程式碼範例示範如何搭配 Amazon SQS 標準佇列使用 Java 訊息服務 (JMS)。如需使用 FIFO 佇列的相關資訊，請參閱 [若要建立 FIFO 佇列](getting-started.md#creating-queue-FIFO)、[同步傳送訊息](getting-started.md#send-messages-synchronously)、[同步接收訊息](getting-started.md#receive-messages-synchronously)。(對於標準和 FIFO 佇列，同步接收訊息是相同的。但是，FIFO 佇列中的訊息包含更多屬性。)

在測試下列範例[使用 JMS 和 Amazon SQS 的先決條件](prerequisites.md)之前，請參閱 中的先決條件。

## ExampleConfiguration.java
<a name="example-configuration"></a>

下列 Java SDK v 1.x 程式碼範例會設定預設佇列名稱、區域，以及要與其他 Java 範例搭配使用的登入資料。

```
/*
 * Copyright 2010-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  https://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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.
 *
 */

public class ExampleConfiguration {
    public static final String DEFAULT_QUEUE_NAME = "SQSJMSClientExampleQueue";
    
    public static final Region DEFAULT_REGION = Region.getRegion(Regions.US_EAST_2);
    
    private static String getParameter( String args[], int i ) {
        if( i + 1 >= args.length ) {
            throw new IllegalArgumentException( "Missing parameter for " + args[i] );
        }
        return args[i+1];
    }
    
    /**
     * Parse the command line and return the resulting config. If the config parsing fails
     * print the error and the usage message and then call System.exit
     * 
     * @param app the app to use when printing the usage string
     * @param args the command line arguments
     * @return the parsed config
     */
    public static ExampleConfiguration parseConfig(String app, String args[]) {
        try {
            return new ExampleConfiguration(args);
        } catch (IllegalArgumentException e) {
            System.err.println( "ERROR: " + e.getMessage() );
            System.err.println();
            System.err.println( "Usage: " + app + " [--queue <queue>] [--region <region>] [--credentials <credentials>] ");
            System.err.println( "  or" );
            System.err.println( "       " + app + " <spring.xml>" );
            System.exit(-1);
            return null;
        }
    }
    
    private ExampleConfiguration(String args[]) {
        for( int i = 0; i < args.length; ++i ) {
            String arg = args[i];
            if( arg.equals( "--queue" ) ) {
                setQueueName(getParameter(args, i));
                i++;
            } else if( arg.equals( "--region" ) ) {
                String regionName = getParameter(args, i);
                try {
                    setRegion(Region.getRegion(Regions.fromName(regionName)));
                } catch( IllegalArgumentException e ) {
                    throw new IllegalArgumentException( "Unrecognized region " + regionName );  
                }
                i++;
            } else if( arg.equals( "--credentials" ) ) {
                String credsFile = getParameter(args, i);
                try {
                    setCredentialsProvider( new PropertiesFileCredentialsProvider(credsFile) );
                } catch (AmazonClientException e) {
                    throw new IllegalArgumentException("Error reading credentials from " + credsFile, e );
                }
                i++;
            } else {
                throw new IllegalArgumentException("Unrecognized option " + arg);
            }
        }
    }
    
    private String queueName = DEFAULT_QUEUE_NAME;
    private Region region = DEFAULT_REGION;
    private AWSCredentialsProvider credentialsProvider = new DefaultAWSCredentialsProviderChain();
    
    public String getQueueName() {
        return queueName;
    }
    
    public void setQueueName(String queueName) {
        this.queueName = queueName;
    }
    
    public Region getRegion() {
        return region;
    }
    
    public void setRegion(Region region) {
        this.region = region;
    }
 
    public AWSCredentialsProvider getCredentialsProvider() {
        return credentialsProvider;
    }
    
    public void setCredentialsProvider(AWSCredentialsProvider credentialsProvider) {
        // Make sure they're usable first
        credentialsProvider.getCredentials();
        this.credentialsProvider = credentialsProvider;
    }
}
```

## TextMessageSender.java
<a name="example-sender"></a>

下列 Java 程式碼範例會先建立文字訊息生產者。

```
/*
 * Copyright 2010-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  https://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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.
 *
 */

public class TextMessageSender {
    public static void main(String args[]) throws JMSException {
        ExampleConfiguration config = ExampleConfiguration.parseConfig("TextMessageSender", args);
        
        ExampleCommon.setupLogging();
        
        // Create the connection factory based on the config       
        SQSConnectionFactory connectionFactory = new SQSConnectionFactory(
                new ProviderConfiguration(),
                AmazonSQSClientBuilder.standard()
                        .withRegion(config.getRegion().getName())
                        .withCredentials(config.getCredentialsProvider())
                );
        
        // Create the connection
        SQSConnection connection = connectionFactory.createConnection();
        
        // Create the queue if needed
        ExampleCommon.ensureQueueExists(connection, config.getQueueName());
            
        // Create the session
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        MessageProducer producer = session.createProducer( session.createQueue( config.getQueueName() ) );
        
        sendMessages(session, producer);
 
        // Close the connection. This closes the session automatically
        connection.close();
        System.out.println( "Connection closed" );
    }
 
    private static void sendMessages( Session session, MessageProducer producer ) {
        BufferedReader inputReader = new BufferedReader(
            new InputStreamReader( System.in, Charset.defaultCharset() ) );
        
        try {
            String input;
            while( true ) { 
                System.out.print( "Enter message to send (leave empty to exit): " );
                input = inputReader.readLine();
                if( input == null || input.equals("" ) ) break;
                
                TextMessage message = session.createTextMessage(input);
                producer.send(message);
                System.out.println( "Send message " + message.getJMSMessageID() );
            }
        } catch (EOFException e) {
            // Just return on EOF
        } catch (IOException e) {
            System.err.println( "Failed reading input: " + e.getMessage() );
        } catch (JMSException e) {
            System.err.println( "Failed sending message: " + e.getMessage() );
            e.printStackTrace();
        }
    }
}
```

## SyncMessageReceiver.java
<a name="example-synchronous-message-receiver"></a>

下列 Java 程式碼範例會建立同步訊息消費者。

```
/*
 * Copyright 2010-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  https://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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.
 *
 */

public class SyncMessageReceiver {
public static void main(String args[]) throws JMSException {
    ExampleConfiguration config = ExampleConfiguration.parseConfig("SyncMessageReceiver", args);
    
    ExampleCommon.setupLogging();
    
    // Create the connection factory based on the config
    SQSConnectionFactory connectionFactory = new SQSConnectionFactory(
            new ProviderConfiguration(),
            AmazonSQSClientBuilder.standard()
                    .withRegion(config.getRegion().getName())
                    .withCredentials(config.getCredentialsProvider())
            );
    
    // Create the connection
    SQSConnection connection = connectionFactory.createConnection();
    
    // Create the queue if needed
    ExampleCommon.ensureQueueExists(connection, config.getQueueName());
        
    // Create the session
    Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
    MessageConsumer consumer = session.createConsumer( session.createQueue( config.getQueueName() ) );

    connection.start();
    
    receiveMessages(session, consumer);

    // Close the connection. This closes the session automatically
    connection.close();
    System.out.println( "Connection closed" );
}

private static void receiveMessages( Session session, MessageConsumer consumer ) {
    try {
        while( true ) {
            System.out.println( "Waiting for messages");
            // Wait 1 minute for a message
            Message message = consumer.receive(TimeUnit.MINUTES.toMillis(1));
            if( message == null ) {
                System.out.println( "Shutting down after 1 minute of silence" );
                break;
            }
            ExampleCommon.handleMessage(message);
            message.acknowledge();
            System.out.println( "Acknowledged message " + message.getJMSMessageID() );
        }
    } catch (JMSException e) {
        System.err.println( "Error receiving from SQS: " + e.getMessage() );
        e.printStackTrace();
    }
}
}
```

## AsyncMessageReceiver.java
<a name="example-asynchronous-message-receiver"></a>

下列 Java 程式碼範例會建立異步訊息消費者。

```
/*
 * Copyright 2010-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  https://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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.
 *
 */

public class AsyncMessageReceiver {
    public static void main(String args[]) throws JMSException, InterruptedException {
        ExampleConfiguration config = ExampleConfiguration.parseConfig("AsyncMessageReceiver", args);
         
        ExampleCommon.setupLogging();          
         
        // Create the connection factory based on the config
        SQSConnectionFactory connectionFactory = new SQSConnectionFactory(
                new ProviderConfiguration(),
                AmazonSQSClientBuilder.standard()
                        .withRegion(config.getRegion().getName())
                        .withCredentials(config.getCredentialsProvider())
                );
         
        // Create the connection
        SQSConnection connection = connectionFactory.createConnection();
         
        // Create the queue if needed
        ExampleCommon.ensureQueueExists(connection, config.getQueueName());
             
        // Create the session
        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
        MessageConsumer consumer = session.createConsumer( session.createQueue( config.getQueueName() ) );
         
        // No messages are processed until this is called
        connection.start();

        ReceiverCallback callback = new ReceiverCallback();
        consumer.setMessageListener( callback );
         
        callback.waitForOneMinuteOfSilence();
        System.out.println( "Returning after one minute of silence" );

        // Close the connection. This closes the session automatically
        connection.close();
        System.out.println( "Connection closed" );
    }
    
    
    private static class ReceiverCallback implements MessageListener {
        // Used to listen for message silence
        private volatile long timeOfLastMessage = System.nanoTime();
         
        public void waitForOneMinuteOfSilence() throws InterruptedException {
            for(;;) {
                long timeSinceLastMessage = System.nanoTime() - timeOfLastMessage;
                long remainingTillOneMinuteOfSilence = 
                    TimeUnit.MINUTES.toNanos(1) - timeSinceLastMessage;
                if( remainingTillOneMinuteOfSilence < 0 ) {
                    break;
                }
                TimeUnit.NANOSECONDS.sleep(remainingTillOneMinuteOfSilence);
            }
        }
         

        @Override
        public void onMessage(Message message) {
            try {
                ExampleCommon.handleMessage(message);
                message.acknowledge();
                System.out.println( "Acknowledged message " + message.getJMSMessageID() );
                timeOfLastMessage = System.nanoTime();
            } catch (JMSException e) {
                System.err.println( "Error processing message: " + e.getMessage() );
                e.printStackTrace();
            }
        }
    }
}
```

## SyncMessageReceiverClientAcknowledge.java
<a name="example-synchronous-receiver-client-acknowledge-mode"></a>

以下 Java 程式碼範例會建立用戶端認可模式的異步消費者。

```
/*
 * Copyright 2010-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  https://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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.
 *
 */

/**
 * An example class to demonstrate the behavior of CLIENT_ACKNOWLEDGE mode for received messages. This example
 * complements the example given in {@link SyncMessageReceiverUnorderedAcknowledge} for UNORDERED_ACKNOWLEDGE mode.
 *
 * First, a session, a message producer, and a message consumer are created. Then, two messages are sent. Next, two messages
 * are received but only the second one is acknowledged. After waiting for the visibility time out period, an attempt to
 * receive another message is made. It's shown that no message is returned for this attempt since in CLIENT_ACKNOWLEDGE mode,
 * as expected, all the messages prior to the acknowledged messages are also acknowledged.
 *
 * This ISN'T the behavior for UNORDERED_ACKNOWLEDGE mode. Please see {@link SyncMessageReceiverUnorderedAcknowledge}
 * for an example.
 */
public class SyncMessageReceiverClientAcknowledge {
 
    // Visibility time-out for the queue. It must match to the one set for the queue for this example to work.
    private static final long TIME_OUT_SECONDS = 1;
 
    public static void main(String args[]) throws JMSException, InterruptedException {
        // Create the configuration for the example
        ExampleConfiguration config = ExampleConfiguration.parseConfig("SyncMessageReceiverClientAcknowledge", args);
 
        // Setup logging for the example
        ExampleCommon.setupLogging();
 
        // Create the connection factory based on the config
        SQSConnectionFactory connectionFactory = new SQSConnectionFactory(
                new ProviderConfiguration(),
                AmazonSQSClientBuilder.standard()
                        .withRegion(config.getRegion().getName())
                        .withCredentials(config.getCredentialsProvider())
                );
 
        // Create the connection
        SQSConnection connection = connectionFactory.createConnection();
 
        // Create the queue if needed
        ExampleCommon.ensureQueueExists(connection, config.getQueueName());
 
        // Create the session  with client acknowledge mode
        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
 
        // Create the producer and consume
        MessageProducer producer = session.createProducer(session.createQueue(config.getQueueName()));
        MessageConsumer consumer = session.createConsumer(session.createQueue(config.getQueueName()));
 
        // 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
        System.out.println("Waiting for visibility timeout...");
        Thread.sleep(TimeUnit.SECONDS.toMillis(TIME_OUT_SECONDS));
 
        // Attempt to receive another message and acknowledge it. This results in receiving no messages since
        // we have acknowledged the second message. Although we didn't explicitly acknowledge the first message,
        // in the CLIENT_ACKNOWLEDGE mode, all the messages received prior to the explicitly acknowledged message
        // are also acknowledged. Therefore, we have implicitly acknowledged the first message.
        receiveMessage(consumer, true);
 
        // Close the connection. This closes the session automatically
        connection.close();
        System.out.println("Connection closed.");
    }
 
    /**
     * Sends a message through the producer.
     *
     * @param producer Message producer
     * @param session Session
     * @param messageText Text for the message to be sent
     * @throws JMSException
     */
    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 a message through the consumer synchronously with the default timeout (TIME_OUT_SECONDS).
     * If a message is received, the message is printed. If no message is received, "Queue is empty!" is
     * printed.
     *
     * @param consumer Message consumer
     * @param acknowledge If true and a message is received, the received message is acknowledged.
     * @throws JMSException
     */
    private static void receiveMessage(MessageConsumer consumer, boolean acknowledge) throws JMSException {
        // Receive a message
        Message message = consumer.receive(TimeUnit.SECONDS.toMillis(TIME_OUT_SECONDS));
 
        if (message == null) {
            System.out.println("Queue is empty!");
        } else {
            // Since this queue has only text messages, cast the message object and print the text
            System.out.println("Received: " + ((TextMessage) message).getText());
 
            // Acknowledge the message if asked
            if (acknowledge) message.acknowledge();
        }
    }
}
```

## SyncMessageReceiverUnorderedAcknowledge.java
<a name="example-synchronous-receiver-unordered-acknowledge-mode"></a>

以下 Java 程式碼範例會建立無順序認可模式的異步消費者。

```
/*
 * Copyright 2010-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  https://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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.
 *
 */

/**
 * An example class to demonstrate the behavior of UNORDERED_ACKNOWLEDGE mode for received messages. This example
 * complements the example given in {@link SyncMessageReceiverClientAcknowledge} for CLIENT_ACKNOWLEDGE mode.
 *
 * First, a session, a message producer, and a message consumer are created. Then, two messages are sent. Next, two messages
 * are received but only the second one is acknowledged. After waiting for the visibility time out period, an attempt to
 * receive another message is made. It's shown that the first message received in the prior attempt is returned again
 * for the second attempt. In UNORDERED_ACKNOWLEDGE mode, all the messages must be explicitly acknowledged no matter what
 * the order they're received.
 *
 * This ISN'T the behavior for CLIENT_ACKNOWLEDGE mode. Please see {@link SyncMessageReceiverClientAcknowledge}
 * for an example.
 */
public class SyncMessageReceiverUnorderedAcknowledge {
 
    // Visibility time-out for the queue. It must match to the one set for the queue for this example to work.
    private static final long TIME_OUT_SECONDS = 1;
 
    public static void main(String args[]) throws JMSException, InterruptedException {
        // Create the configuration for the example
        ExampleConfiguration config = ExampleConfiguration.parseConfig("SyncMessageReceiverUnorderedAcknowledge", args);
 
        // Setup logging for the example
        ExampleCommon.setupLogging();
 
        // Create the connection factory based on the config
        SQSConnectionFactory connectionFactory = new SQSConnectionFactory(
                new ProviderConfiguration(),
                AmazonSQSClientBuilder.standard()
                        .withRegion(config.getRegion().getName())
                        .withCredentials(config.getCredentialsProvider())
                );
 
        // Create the connection
        SQSConnection connection = connectionFactory.createConnection();
 
        // Create the queue if needed
        ExampleCommon.ensureQueueExists(connection, config.getQueueName());
 
        // Create the session  with unordered acknowledge mode
        Session session = connection.createSession(false, SQSSession.UNORDERED_ACKNOWLEDGE);
 
        // Create the producer and consume
        MessageProducer producer = session.createProducer(session.createQueue(config.getQueueName()));
        MessageConsumer consumer = session.createConsumer(session.createQueue(config.getQueueName()));
 
        // 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
        System.out.println("Waiting for visibility timeout...");
        Thread.sleep(TimeUnit.SECONDS.toMillis(TIME_OUT_SECONDS));
 
        // Attempt to receive another message and acknowledge it. This results in receiving the first message since
        // we have acknowledged only the second message. In the UNORDERED_ACKNOWLEDGE mode, all the messages must
        // be explicitly acknowledged.
        receiveMessage(consumer, true);
 
        // Close the connection. This closes the session automatically
        connection.close();
        System.out.println("Connection closed.");
    }
 
    /**
     * Sends a message through the producer.
     *
     * @param producer Message producer
     * @param session Session
     * @param messageText Text for the message to be sent
     * @throws JMSException
     */
    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 a message through the consumer synchronously with the default timeout (TIME_OUT_SECONDS).
     * If a message is received, the message is printed. If no message is received, "Queue is empty!" is
     * printed.
     *
     * @param consumer Message consumer
     * @param acknowledge If true and a message is received, the received message is acknowledged.
     * @throws JMSException
     */
    private static void receiveMessage(MessageConsumer consumer, boolean acknowledge) throws JMSException {
        // Receive a message
        Message message = consumer.receive(TimeUnit.SECONDS.toMillis(TIME_OUT_SECONDS));
 
        if (message == null) {
            System.out.println("Queue is empty!");
        } else {
            // Since this queue has only text messages, cast the message object and print the text
            System.out.println("Received: " + ((TextMessage) message).getText());
 
            // Acknowledge the message if asked
            if (acknowledge) message.acknowledge();
        }
    }
}
```

## SpringExampleConfiguration.xml
<a name="example-spring-configuration"></a>

以下 XML 程式碼範例是 [SpringExample.java](#example-spring) 的 Bean 組態檔案。

```
<!--
    Copyright 2010-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.

    Licensed under the Apache License, Version 2.0 (the "License").
    You may not use this file except in compliance with the License.
    A copy of the License is located at

    https://aws.amazon.com/apache2.0

    or in the "license" file accompanying this file. This file 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.
-->

<?xml version="1.0" encoding="UTF-8"?>
<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
    ">
    
    <bean id="CredentialsProviderBean" class="com.amazonaws.auth.DefaultAWSCredentialsProviderChain"/>
    
    <bean id="ClientBuilder" class="com.amazonaws.services.sqs.AmazonSQSClientBuilder" factory-method="standard">
        <property name="region" value="us-east-2"/>
        <property name="credentials" ref="CredentialsProviderBean"/>               
    </bean>
    
    <bean id="ProviderConfiguration" class="com.amazon.sqs.javamessaging.ProviderConfiguration">
        <property name="numberOfMessagesToPrefetch" value="5"/>
    </bean>
    
    <bean id="ConnectionFactory" class="com.amazon.sqs.javamessaging.SQSConnectionFactory">
        <constructor-arg ref="ProviderConfiguration" />
        <constructor-arg ref="ClientBuilder" />
    </bean>
    
    <bean id="Connection" class="javax.jms.Connection"
        factory-bean="ConnectionFactory"
        factory-method="createConnection"
        init-method="start"
        destroy-method="close" />
    
    <bean id="QueueName" class="java.lang.String">
        <constructor-arg value="SQSJMSClientExampleQueue"/>
    </bean>
</beans>
```

## SpringExample.java
<a name="example-spring"></a>

以下 Java 程式碼範例會使用 Bean 組態檔案來初始化物件。

```
/*
 * Copyright 2010-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  https://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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.
 *
 */
                
public class SpringExample {
    public static void main(String args[]) throws JMSException {
        if( args.length != 1 || !args[0].endsWith(".xml")) {
            System.err.println( "Usage: " + SpringExample.class.getName() + " <spring config.xml>" );
            System.exit(1);
        }
        
        File springFile = new File( args[0] );
        if( !springFile.exists() || !springFile.canRead() ) {
            System.err.println( "File " + args[0] + " doesn't exist or isn't readable.");
            System.exit(2);
        }
        
        ExampleCommon.setupLogging();
        
        FileSystemXmlApplicationContext context = 
            new FileSystemXmlApplicationContext( "file://" + springFile.getAbsolutePath() );
        
        Connection connection;
        try {
            connection = context.getBean(Connection.class);
        } catch( NoSuchBeanDefinitionException e ) {
            System.err.println( "Can't find the JMS connection to use: " + e.getMessage() );
            System.exit(3);
            return;
        }
        
        String queueName;
        try {
            queueName = context.getBean("QueueName", String.class);
        } catch( NoSuchBeanDefinitionException e ) {
            System.err.println( "Can't find the name of the queue to use: " + e.getMessage() );
            System.exit(3);
            return;
        }
        
        if( connection instanceof SQSConnection ) {
            ExampleCommon.ensureQueueExists( (SQSConnection) connection, queueName );
        }
        
        // Create the session
        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
        MessageConsumer consumer = session.createConsumer( session.createQueue( queueName) );
        
        receiveMessages(session, consumer);
 
        // The context can be setup to close the connection for us
        context.close();
        System.out.println( "Context closed" );
    }
 
    private static void receiveMessages( Session session, MessageConsumer consumer ) {
        try {
            while( true ) {
                System.out.println( "Waiting for messages");
                // Wait 1 minute for a message
                Message message = consumer.receive(TimeUnit.MINUTES.toMillis(1));
                if( message == null ) {
                    System.out.println( "Shutting down after 1 minute of silence" );
                    break;
                }
                ExampleCommon.handleMessage(message);
                message.acknowledge();
                System.out.println( "Acknowledged message" );
            }
        } catch (JMSException e) {
            System.err.println( "Error receiving from SQS: " + e.getMessage() );
            e.printStackTrace();
        }
    }
}
```

## ExampleCommon.java
<a name="example-common"></a>

以下 Java 程式碼範例檢查 Amazon SQS 佇列是否存在，如果不存在，則建立此佇列。另外還包含範例記錄程式碼。

```
/*
 * Copyright 2010-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  https://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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.
 *
 */

public class ExampleCommon {
    /**
     * A utility function to check the queue exists and create it if needed. For most  
     * use cases this is usually done by an administrator before the application is run. 
     */
    public static void ensureQueueExists(SQSConnection connection, String queueName) 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) ) {
            client.createQueue( queueName );
        }
    }
 
    public static void setupLogging() {
        // Setup logging
        BasicConfigurator.configure();
        Logger.getRootLogger().setLevel(Level.WARN);
    }
 
    public static void handleMessage(Message message) throws JMSException {
        System.out.println( "Got message " + message.getJMSMessageID() );
        System.out.println( "Content: ");
        if( message instanceof TextMessage ) {
            TextMessage txtMessage = ( TextMessage ) message;
            System.out.println( "\t" + txtMessage.getText() );
        } else if( message instanceof BytesMessage ){
            BytesMessage byteMessage = ( BytesMessage ) message;
            // 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);
            System.out.println( "\t" +  Base64.encodeAsString( bytes ) );
        } else if( message instanceof ObjectMessage ) {
            ObjectMessage objMessage = (ObjectMessage) message;
            System.out.println( "\t" + objMessage.getObject() );
        }
    }
}
```

# Amazon SQS 支援的 JMS 1.1 實作
<a name="supported-implementations"></a>

Amazon SQS Java 訊息程式庫支援以下 [JMS 1.1 實作](http://docs.oracle.com/javaee/6/api/javax/jms/package-summary.html)。如需 Amazon SQS Java 訊息程式庫支援的特性和功能相關資訊，請參閱 [Amazon SQS 常見問答集](https://aws.amazon.com/sqs/faqs/)。

## 支援的常用界面
<a name="supported-common-interfaces"></a>
+ `Connection`
+ `ConnectionFactory`
+ `Destination`
+ `Session`
+ `MessageConsumer`
+ `MessageProducer`

## 支援的訊息類型
<a name="supported-message-types"></a>
+ `ByteMessage`
+ `ObjectMessage`
+ `TextMessage`

## 支援的訊息認可模式
<a name="supported-message-acknowledgement-modes"></a>
+ `AUTO_ACKNOWLEDGE`
+ `CLIENT_ACKNOWLEDGE`
+ `DUPS_OK_ACKNOWLEDGE`
+ `UNORDERED_ACKNOWLEDGE`

**注意**  
`UNORDERED_ACKNOWLEDGE` 模式並不屬於 JMS 1.1 規格。此模式可協助 Amazon SQS 允許 JMS 用戶端明確認可訊息。

## JMS 定義標頭和預訂屬性
<a name="jms-defined-headers-reserved-properties"></a>

### 進行傳送訊息
<a name="for-sending-messages"></a>

傳送訊息時，您可以設定每個訊息的以下標頭和屬性：
+ `JMSXGroupID` (FIFO 佇列為必要，不允許使用於標準佇列)
+ `JMS_SQS_DeduplicationId` (FIFO 佇列為選用，不允許使用於標準佇列)

傳送訊息後，Amazon SQS 會設定每個訊息的以下標頭和屬性：
+ `JMSMessageID`
+ `JMS_SQS_SequenceNumber` (僅限於 FIFO 佇列)

### 接收訊息
<a name="for-receiving-messages"></a>

接收訊息後，Amazon SQS 會設定每個訊息的以下標頭和屬性：
+ `JMSDestination`
+ `JMSMessageID`
+ `JMSRedelivered`
+ `JMSXDeliveryCount`
+ `JMSXGroupID` (僅限於 FIFO 佇列)
+ `JMS_SQS_DeduplicationId` (僅限於 FIFO 佇列)
+ `JMS_SQS_SequenceNumber` (僅限於 FIFO 佇列)