2003 г
Стив Мюнх,
Стивен Фернстайн
Работа с XML-сообщениями
(Working with XML Messages, by Steve Muench and Steven Feuerstein)
Источник: журнал Oracle Professional, октябрь 2001,
http://www.pinnaclepublishing.com/OP/OPMag.nsf/WebIndexByIssue/
07F224E8D56E3EDF85256AB60073EBB1?opendocument&login
В этой статье из цикла, посвященного XML, Стив Мюнх и Стивен Фернстайн рассматривают примеры использования XML в качестве механизма обмена структурированными данными между приложениями.
В этой статье мы сначала разберем синхронные подходы, такие как отправка и получение XML-сообщений через HTTP, а затем рассмотрим основы механизма Oracle's Advanced Queuing (усовершенствованное управление сообщениями) для поддержки асинхронных сообщений, передаваемых между приложениями.
Отправка и получение XML между серверами
Поскольку XML может представлять структурированные данные открытым стандартным способом, он быстро становится предпочтительным методом обмена данными через Web. Через год или два он станет основным методом. Сайты, которые работают с информацией в виде HTML— удобном, прежде всего, для человеческих глаз,—добавят возможность использования информации в формате, основанном на XML, что позволит другим серверам гораздо проще использовать эти данные. Фирмы, действующие приложения которых позволяют пользователю взаимодействовать только через HTML-форму, основанную на Web, будут вынуждены добавить возможность принимать присылаемые запросы в формате XML, чтобы сделать возможным обмен данными между фирмами.
Таким образом, Web быстро разовьется, чтобы предоставить разработчикам коммерческих приложений море информационных услуг, основанных на XML, что позволит вашему приложению проверить статус заказа, отменить бронирование или заказать билет на рейс, просто отправив или получив соответствующие XML-дейтаграммы. Само собой разумеется, что умение писать программы, которые получают и отправляют XML, является важным навыком для любого разработчика, создающего следующее поколение Web-приложений. Здесь мы рассмотрим, как это можно реализовать с помощью PL/SQL в Oracle8i.
Давайте уточним, что когда мы говорим об “отправке XML другому серверу через Web”, имеется в виду отправка на HTTP POST-запроса, содержащего XML-документ в теле запроса с MIME Content-Type text /xml.
Следовательно, основной составляющей в отправке XML через Web является умение отправлять HTTP POST запрос. Поскольку http-протокол является набором соглашений, основанным на TCP/IP, мы можем использовать встроенный пакет Oracle8i utl_tcp для построения нашего HTTP POST-решения.
Пакет utl_tcp вынуждает TCP/IP-подпрограммы, лежащие в основе, открыть соединение, записать данные в соединение и прочитать данные обратно из соединения. Записав соответствующие HTTP команды и данные в соединение, мы сможем легко написать нашу программу передачи данных, используя PL/SQL. Например, чтобы передать XML документ, показанный на Листинге 1, Web сервису, расположенному по URL http://services.example.com:2775/add-news-story.xsql, нам необходимо сделать следующее:
- Открыть TCP/IP соединение к машине services.example.com на порт 2775.
- Написать заголовок в соединении:
HTTP POST /add-news-story.xsql HTTP/1.0
Content-Type: text/xml
Content-Length: 240
- Написать пустую строку в соединение, чтобы отделить заголовок от тела.
- Написать XML документ в соединение.
Затем нужно прочитать ответ из соединения. В прилагаемом Download файле, можно посмотреть полный исходный код пакета, который реализует такое HTTP поведение, используя возможности, предоставляемые пакетом utl_tcp. В статье мы рассмотрим только API или спецификацию пакета. (см Листинг 2).
Этот пакет позволяет легко отправлять (HTTP POST) или получать (HTTP GET) любую информацию через Web, ограниченную только длиной PL/SQL переменной. Усовершенствованная версия может использовать символьный LOB для обработки данных большого размера.
На основе процедур отправки и получения пакета http мы можем построить другой вспомогательный пакет xml_http, который сделает отправку и получение информации, основанной на XML, более простой. В Листинге 3 приведена спецификация пакета xml_http.
В реализации xml_http в Листинге 4 вы увидите, что эти процедуры просто предоставляют дополнительные удобства, позволяя напрямую отправлять объект xmldom.DOMDocument, а также получать результат отправки (POST) или получения (GET) напрямую в виде xmldom.DOMDocument для дальнейшей обработки. Обратите внимание на использование пакета xml, который мы рассматривали в предыдущей статье, для облегчения разбора.
Теперь, когда все подпрограммы на своих местах, пришло время проверить их в работе. Во-первых, мы попробуем передать новости на сервер, который поддерживает “сервис передачи новостей”. На Рисунке 1 показан XML обмен через HTTP, который осуществляется через сервер нашей базы данных и сервис новостей.
Запрашивающая сторона передает новости, в ожидаемом XML формате, подобном формату новостей Moreover.com, а сервис возвращает, основанное на XML-сообщение о статусе запроса. В этом примере, возвращаемое XML-сообщение содержит только статус сообщения, однако, дейтаграмма, возвращаемая сервером, может содержать и другую полезную информацию.
На Листинге 5 представлена процедура postNewsStory, которая делает следующее:
- Определяет значения аргументов, переданных в функцию, на соответствующие места в XML дейтаграмме <moreovernews>.
- Передает дейтаграмму новостей на URL Web сервиса, используя xml_http.post.
- Проверяет содержание вернувшегося XML документа, используя xpath.test, чтобы проверить успешно ли завершился запрос на отправку (POST).
Мы можем быстро проверить функцию из SQL*Plus, создав переменную SQL*Plus с именем status, и запустив функцию вроде этой:
SQL> variable status varchar2(10);
SQL> exec :status := postNewsStory('Она
работает!','Стив','http://someserver/somepage.html');
PL/SQL procedure successfully completed.
SQL> print status
STATUS
------------
Success
Печать значения переменной status показывает, что запрос был успешным.
Далее, мы проверим пример получения (HTTP GET). Иногда Web сервисы просто принимают информацию о задаче, которую им необходимо выполнить, в качестве параметров URL. В этих случаях нет необходимости передавать какой-либо XML документ. Вместо этого мы только делаем HTTP GET на URL сервиса с соответствующим значением параметра, добавленным в конец URL.
На Рисунке 2 показан обмен между нашей базой данных и Web сервисом, который позволяет нам искать название аэропорта, по трехбуквенному сокращению. База данных, запущенная на сайте, предлагающем услугу “Поиск аэропорта”, содержит трехбуквенные коды и описания более 10000 аэропортов мира. Мы можем искать наименование для некоего аэропорта с кодом XYZ, выполнив HTTP GET на URL:
http://ws5.olab.com/xsql/demo/airport/airport.xsql?airport=XYZ.
Для этого, создадим функцию airportDescription, которая делает следующее:
- Приклеивает значение аргумента, передаваемого функции, в конец Web сервиса URL.
- Получает дейтаграмму от Web сервиса, используя xml_http.get.
- Проверяет содержимое возвращаемого XML документа, используя xpath.test, чтобы увидеть успешно ли завершился запрос на передачу (POST).
Код этой функции приведен в Листинге 6.
Снова, мы можем быстро проверить нашу новую функцию airportDescription из SQL*Plus, как показано ниже, чтобы увидеть какой аэропорт соответствует абревиатуре XML:
SQL> VARIABLE descrip VARCHAR2(80);
SQL> EXEC :descrip := airportDescription('XML');
PL/SQL procedure successfully completed.
SQL> PRINT descrip
DESCRIP
-------------------------
Minlaton, Sa, Australia
Итак, используя этот сервис, мы обнаружили, что, чтобы действительно отправиться в сердце XML страны, нам необходимо полететь в Qantas.
Обработка асинхронных XML-сообщений в очередях
Обрабатываете ли вы банковских клиентов в диалоговом окне или заказы покупателей на Web сайте, и теория, и практика утверждают, что очереди – это оптимальный подход к обработке заданий. Очереди позволяют заданиям накапливаться упорядоченным образом, и позволяют гибкому количеству исполнителей обрабатывать задания так быстро как это возможно. В часы пик больше исполнителей могут быть привлечены к работе. В свободное время, дежурная команда может удерживать фронт. В нашем сценарии очереди заданий обрабатываются очередью Oracle Advanced Queueing, чье содержимое управляется таблицей очередей, а исполнители – это программы, которые выводят из очереди сообщения и обрабатывают их.
Поскольку возможности Oracle's AQ в значительной степени поддерживаются базой данных Oracle8i, сообщения, которые вы помещаете в очередь имеют точно такие же гарантии надежности, как и все данные базы данных. Проще говоря, это означает, что сообщения надежно доставляются и никогда не будут потеряны. Oracle AQ обрабатывает даже автоматическую передачу сообщений между очередями на разных машинах и между различными системами очередей. Итак, должно быть понятно, что стоит потратить время, чтобы разобраться, как воспользоваться такой мощной возможностью для асинхронного обмена XML-сообщениями.
Рисунок 3 иллюстрирует основную идею очередей в базе данных. Один или несколько процессов ставят задание, которое должно быть сделано, в очередь, а другие рабочие процессы извлекают сообщение из очереди для обработки. По умолчанию используется интуитивно “справедливый” механизм – первый вошел, первый вышел (FIFO) – но AQ поддерживает также многие другие методы обслуживания очереди. Простым примером может быть обслуживание сначала высоко приоритетных заказов, или заказов от платиновых клиентов.
Настроить очередь для использования легко. Если у вас есть роль AQ_ADMINISTRATOR_ROLE, вы можете выполнять все необходимые операции для создания, изменения и удаления очередей и таблиц очередей. Если DBA, например SYS, дал вам следующие права, вы сможете все это делать:
connect sys/password
GRANT AQ_ADMINISTRATOR_ROLE TO xmlbook;
GRANT EXECUTE ON SYS.DBMS_AQADM TO xmlbook;
GRANT EXECUTE ON SYS.DBMS_AQ TO xmlbook;
GRANT EXECUTE ON SYS.DBMS_AQIN TO xmlbook;
Мы создадим очередь xml_msg_queue для хранения наших XML-сообщений, где они будут поджидать дальнейшей обработки. Очередь связана с соответствующей таблицей, используемой для хранения и предоставления возможности запроса сообщений, стоящих в очереди, поэтому мы сначала создадим таблицу queue, затем очередь, которая живет в этой таблице, запустив следующий анонимный PL/SQL блок:
-- createXMLMessageQueue.sql
DECLARE
queuetablename VARCHAR2 (30) := 'xml_msg_queuetable';
queuename VARCHAR2 (30) := 'xml_msg_queue';
BEGIN
-- Удаляем таблицу очередей,
-- игнорируя ошибку, если ее не было
BEGIN
DBMS_AQADM.drop_queue_table (queuetablename);
EXCEPTION
WHEN OTHERS
THEN NULL;
END;
-- Создаем таблицу очередей
DBMS_AQADM.create_queue_table (
queue_table=> queuetablename,
queue_payload_type=> 'RAW'
);
-- Создаем очередь, основанную на данной таблице
DBMS_AQADM.create_queue (queuename,queuetablename);
-- Открываем очередь
DBMS_AQADM.start_queue (queuename);
END;
Обратите внимание, что мы использовали простейший тип очереди, который поддерживает бинарную полезную нагрузку до 32KB, для того, чтобы узнать о механизмах. Когда вы узнаете о том, как работать с XML-сообщениями в этой простейшей очереди, вы обнаружите, что эксперименты с другими возможностями AQ станут гораздо проще. Как мы уже делали с другими связанными с XML технологиями, которые мы планировали использовать снова и снова, давайте построим вспомогательный пакет для работы с XML-сообщениями и дополнительными очередями. На Листинге 7 показана спецификация пакета xmlq. Она очень проста. Она содержит только две подпрограммы: для постановки в очередь – enqueue и для извлечения из очереди – dequeue. Процедура enqueue принимает на вход xmldom.DOMDocument и имя очереди, в которую должно быть поставлено XML-сообщение. Функция dequeue принимает имя очереди и флаг ожидания, и возвращает сообщение из очереди в виде xmldom.DOMDocument.
Реализация пакета xmlq (представленного в Листинге 8) почти также проста, как его спецификация. Единственное о чем стоит упомянуть, это использование функции utl_raw.cast_to_raw для преобразования переданного сообщения XML в блок сырых байтов, и функции utl_raw.cast_to_varchar2 для выполнения обратной операции при извлечении из очереди. Если при вызове функции флаг ожидания имеет значение TRUE, мы устанавливаем соответствующие опции в структуре записи опций извлечения из очереди. Это говорит Oracle AQ о том, что если в очереди нет ожидающих нас сообщений, мы собираемся спать, пока не прибудут сообщения.
Обратите внимание, что в спецификации пакета xmlq мы используем прагму EXCEPTION_INIT, чтобы связать значащее имя исключения, например xmlq.queue_empty, с кодом ошибки, которая возникает, когда мы пытаемся извлечь из очереди сообщение без ожидания, и там нет сообщений.
Можно проиллюстрировать постановку в очередь XML заказов следующим простым анонимным PL/SQL блоком. Он создает и ставит в очередь пять новых XML-сообщений о заказах, вызывая xmlq.enqueue. Каждый заказ выглядит следующим образом <order id="101"/>:
-- xml_Enqueue_Test.sql
set serveroutput on
DECLARE
xmldoc xmldom.DOMDocument;
xmlOrder VARCHAR2(200);
BEGIN
dbms_output.put_line(
'Тест постановки в очередь XML в сессии '|userenv('SESSIONID'));
FOR ordId IN 101..105 LOOP
-- Построение маленького XML документа заказа
-- типа <order id="xxx"/>
xmlOrder := '<order id="'||ordId||'"/>';
-- Разбор текущего документа заказа
xmldoc := xml.parse(xmlOrder);
-- Постановка текущего заказа в очередь 'xml_msg_queue'
xmlq.enqueue(xmldoc,'xml_msg_queue');
-- Освобождение текущего XML документа
xml.freeDocument(xmldoc);
-- Печать журнального сообщения
dbms_output.put_line('Заказ '||ordId||' помещен в очередь.');
END LOOP;
END;
Запуск этого кода показывает, что наши первые пять заказов находятся теперь на пути к “конвейеру” технологических шагов обработки заказа, управляемому очередью:
XML Enqueue Test in Session 1682
Placed order 101 in queue.
Placed order 102 in queue.
Placed order 103 in queue.
Placed order 104 in queue.
Placed order 105 in queue.
Войдя из другой сессии SQL*Plus, мы можем проиллюстрировать удаление заказов из очереди. Как показано в Листинге 9, мы выполняем цикл, который вызывает xmlq.dequeue с флагом ожидания установленным в false. Добавив раздел обработки исключения, который включает предложение WHEN xmlq.queue_empty мы сможем явно перехватить и обработать это условие.
Запуск этого кода показывает FIFO природу очереди, которая была создана со всеми установками по умолчанию, такова и наша xml_msg_queue. Одно за другим сообщения выбирались из очереди, до тех пор, пока мы не опустошили всю очередь:
XML Dequeue Test in Session 1684
Processing Order #101
Processing Order #102
Processing Order #103
Processing Order #104
Processing Order #105
No more orders to process.
XML: интеграл и интегрированный
Эта статья очень ясно показывает как хорошо и легко XML технология сочетается с другой функциональностью Oracle, в данном случае Advanced Queueing. В следующем номере Oracle Professional, мы рассмотрим, как использовать XML SQL Утилиту для производства и преобразования результатов XML запроса.
Приложение: Скачайте файл FEUER.ZIP