Рис.1. Основные концепции очереди
В качестве повторения определим основные понятия, которые используются при работе с очередями:
URL очереди: каждая очередь, будучи отдельной сущностью, имеет свой собственный URL (конечную точку входа), с помощью которой можно получить к ней доступ. Формат URL выглядит стандартно для сервисов хранилищ Windows Azure: http://<storage account>.queue.core.windows.net/<queue>
Account: Аккаунт хранилища Windows Azure необходим для управления вашими данными – все очереди, блобы и прочие сервисы хранилища ассоциируются с вашим аккаунтом с помощью аккаунта хранилища. Максимальный суммарный объем данных, который вы можете хранить в аккаунте хранилища – 100Тб.
Queue: Очередь (queue) необходима для хранения сообщений.
Message: Сообщение(message) – сущность в любом формате до 64Кб.
Для того, чтобы продолжить разработку, создадим новый Java-проект и внесем в него некоторые изменения в Java-проект:
1. Добавьте новый класс TestJavaStorage в Java-проект. Для этого необходимо щелкнуть правой кнопкой мыши на проекте и нажать New, после чего нажать Class (рис.2).
Рис.2. Добавление Java-класса.
import com.microsoft.windowsazure.services.core.storage.*; import com.microsoft.windowsazure.services.queue.client.*;
public static final String ConnectionString = "DefaultEndpointsProtocol=http;AccountName=[accountName]; AccountKey=[accountKey]";
String ConnectionString = RoleEnvironment.getConfigurationSettings().get("StorageConnectionString");
<ConfigurationSettings>
<Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="…" /> …
</ConfigurationSettings>
В данном примере используется первый подход и используется локальный эмулятор хранилища, однако вам ничего не мешает использовать этот код для доступа к облачному хранилищу – достаточно лишь поменять значение параметра строки подключения.
Код, предназначенный для управления очередями, аналогичен коду, используемому для управления очередями в C#. Поскольку используемые конструкции достаточно подробно рассмотрены по прилагающимся ссылкам в начале статьи, останавливаться подробно на этих моментах не будем – приведу лишь общий код с комментариями.
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.net.URISyntaxException; import java.security.InvalidKeyException; import java.util.EnumSet; import com.microsoft.windowsazure.services.core.storage.*; import com.microsoft.windowsazure.services.queue.client.CloudQueue; import com.microsoft.windowsazure.services.queue.client.CloudQueueClient; import com.microsoft.windowsazure.services.queue.client.CloudQueueMessage; import com.microsoft.windowsazure.services.queue.client.MessageUpdateFields; import com.microsoft.windowsazure.services.blob.client.*; public class TestJavaStorage { public static final String StorageConnectionString = "UseDevelopmentStorage=true"; public static CloudQueueClient getQueueClient() throws InvalidKeyException, URISyntaxException { CloudStorageAccount storageAccount = CloudStorageAccount .parse(StorageConnectionString); return storageAccount.createCloudQueueClient(); } public static CloudQueue createQueue(CloudQueueClient queueClient, String name) throws InvalidKeyException, URISyntaxException, StorageException { CloudQueue queue = queueClient.getQueueReference(name); queue.createIfNotExist(); return queue; } public static void addMessageToQueue(CloudQueue queue, CloudQueueMessage message) throws InvalidKeyException, URISyntaxException, StorageException { queue.addMessage(message); } public static CloudQueueMessage peekMessage(CloudQueue queue) throws InvalidKeyException, URISyntaxException, StorageException { CloudQueueMessage message = queue.peekMessage(); return message; } public static void deleteMessage(CloudQueue queue, CloudQueueMessage message) { try { queue.deleteMessage(message); System.out.println("Сообщение с ID "+message.getId() + " удалено"); } catch (StorageException e) { e.printStackTrace(); } } public static void updateMessage(CloudQueue queue, CloudQueueMessage message, String newContent) { message.setMessageContent(newContent); EnumSet<MessageUpdateFields> updateFields = EnumSet.of( MessageUpdateFields.CONTENT, MessageUpdateFields.VISIBILITY); try { queue.updateMessage(message, 60, updateFields, null, null); } catch (StorageException e) { e.printStackTrace(); } } public static void deleteMessages(CloudQueue queue) throws StorageException { //Сообщения из очереди забираются в количестве 20 штук, в это время таймаут на невидимость для других обработчиков //устанавливается в 300 секунд. for (CloudQueueMessage message : queue.retrieveMessages(20, 300, null, null)) { try { System.out.println("Сообщение с ID" + message.getId() + " и содержимым " + message.getMessageContentAsString() + " подготовлено к удалению"); queue.deleteMessage(message); } catch (StorageException e) { e.printStackTrace(); } } } public static void getQueueAttributes(CloudQueue queue) { try { queue.downloadAttributes(); } catch (StorageException e) { e.printStackTrace(); } long cachedMessageCount = queue.getApproximateMessageCount(); System.out .println("Примерное количество сообщений в очереди под названием " + queue.getName() + " с URI " + queue.getUri() + ":" + cachedMessageCount); } public static void deleteQueue(CloudQueue queue) { try { queue.delete(); } catch (StorageException e) { e.printStackTrace(); } } public static void main(String args[]) throws InvalidKeyException, URISyntaxException, StorageException { // Создание клиента очереди CloudQueueClient client = getQueueClient(); // Создание очереди с именем myqueue CloudQueue queue = createQueue(client, "myqueue"); // Создание нового сообщения для очереди. CloudQueueMessage message = new CloudQueueMessage( "This is the test message sent to the queue"); addMessageToQueue(queue, message); // Получение первого сообщения из начала очереди, обновление его // содержимого. Можно получать несколько сообщений (до 32) CloudQueueMessage retrievedMessage = queue.retrieveMessage(); updateMessage(queue, retrievedMessage, "Содержимое обновлено на русский язык."); getQueueAttributes(queue); // Удаление сообщений происходит в два этапа - при вызове // retrieveMessage получается первое сообщение в очереди. // После этого оно становится "невидимым" для обработчиков на 30 секунд // (по умолчанию, можно менять). // После этого необходимо вызвать для полного удаление сообщения метод // deleteMessage. deleteMessage(queue,retrievedMessage); //вторая версия метода удаления - удаление нескольких сообщений. deleteMessages(queue); // удаление очереди deleteQueue(queue); } }
Обратите внимание на то, что в коде много раз выбрасывается набор исключений FileNotFoundException(может произойти с конструкторами FileInput(Output)Stream), StorageException (типичное исключение для клиентской библиотеки Windows Azure), URISyntaxException (выбрасывается методом getUri()).
В приведенном коде выбрасываемые исключения никак не обрабатываются. Избегайте подобного подхода, так как это ведёт к непредсказуемому поведению вашего приложения.
Рис.3. Запуск простого Java-проекта.
В консоли вы должны увидеть результат (рис.4).
Рис.4. Ожидаемый результат выполнения программы.
Для того, чтобы просмотреть содержимое хранилища, вы можете воспользоваться либо Server Explorer в Visual Studio 2010 либо специальной утилитой Windows Azure Storage Explorer (рис. 4).
Рис. 4. Использование Windows Azure Storage Explorer.
Будьте внимательны – если вы хотите посмотреть содержимое хранилища очередей и не находите там ни одного сообщения – это нормально, так как в коде используется не только удаление сообщений, но и методы retrieveMessage(), которые забирают сообщение из очереди.
Fernando Lugão Veltem edited Revision 4. Comment: alter title and tags