Обеспечить асинхронное взаимодействие с веб-сервисом по протоколу HTTP можно не только с помощью Oracle SOA Suite, но и с помощью Oracle Service Bus. Основная сложность при этом заключается в том, что Oracle Service Bus не содержит встроенных средств сохранения состояния, поэтому необходимо будет каким-то образом сохранить во внешней памяти URL сервиса обратного вызова и идентификатор сообщения, на которое мы отвечаем. Так же нам нужно будет самостоятельно сформировать заголовок ответного SOAP-сообщения, соответствующий спецификации WS-Addressing. Давайте посмотрим как это можно сделать.
Сохранить во внешней памяти URL сервиса обратного вызова, т.е. того сервиса, на который нам необходимо отправить асинхронный ответ после завершения работы, и идентификатор поступившего сообщения можно несколькими способами. Один из них - использовать между OSB и реализацией сервиса JMS-очередь и выставить соответствующие дополнительные свойства записываемому в нее сообщению. Аналогично для передачи ответа от реализации сервиса к OSB использовать другую JMS-очередь - очередь ответов. Соответственно, на шине должны присутствовать прокси-сервис, принимающий запрос по протоколу HTTP, извлекающий из его заголовка URL сервиса обратного вызова и идентификатор сообщения и помещающий данный запрос в очередь запросов, а так же прокси-сервис, слушающий очередь ответов и формирующий сообщение для сервиса обратного вызова. При этом в данный прокси-сервис необходимо каким-то образом передать сохраненные в первой очереди - очереди запросов - URL сервиса обратного вызова и идентификатор сообщения-запроса. Сделать это можно с помощью тех же дополнительных свойств JMS-сообщения, помещаемого реализацией сервиса в очередь ответов. Получается, что данная схема накладывает одно ограничение на реализацию сервиса - та должна перекладывать значения дополнительных свойств JMS-сообщения запроса в JMS-сообщение ответа.
Логика первого прокси-сервиса - AsyncProxyService проста. Данный прокси-сервис с помощью HTTP-транспорта принимает SOAP-запросы. Затем принятое сообщение с помощью бизнес-сервиса WriteRequestBusinessService помещается в соответствующую JMS-очередь.
Наиболее интересная задача, решаемая данным прокси-сервисов - формирование дополнительных свойств JMS-сообщения: MessageId - идентификатор принятого сообщения-запроса и Address - URL сервиса обратного вызова. Данные свойства формируются с помощью действия Transport Header.
Извлекаются значения данных свойств из соответствующих полей заголовка SOAP-сообщения: MessageId из поля MessageID:
а Address - из поля ReplyTo/Address:
В приведенных выражениях префикс wsa05 соответствует пространству имен http://www.w3.org/2005/08/addressing.
Рассмотрим пример:
При получении данного запроса прокси-сервис AsyncProxyService сформирует следующее JMS-сообщение:
Для чтения JMS-очереди ответов и формирования обратного вызова используется прокси-сервис AsyncCallbackProxyService. Данный прокси-сервис формирует соответствующие стандарту WS-Addressing поля заголовка SOAP-сообщения и отправляет данное сообщение на указанный в дополнительном свойстве Address JMS-сообщения URL сервиса обратного вызова.
Формирование заголовка SOAP-сообщения осуществляется с помощью действия Replace. Необходимо сформировать заголовок, содержащий следующие поля:
Целиком выражение для формирования заголовка будет выглядеть следующим образом:
Для отправки ответа по адресу, сохраненному в поле Address, используется действие Routing Options. Данное действие позволяет изменять адрес, на который отправляется ответ, параметры участия сервиса в транзакции (Quality of Service, QoS), режим обмена (Request или Request-Response), интервал между повторами и количество повторов в случае сбоя, а так же приоритет сообщения.
В данном случае нам необходимо изменить параметр URI, подставив в него значение поля Address, получить которое можно с помощью следующего выражения:
При этом очень важно помнить, чтобы дополнительные свойства JMS-сообщения были доступны в прокси-сервисе, необходимо выставить значение поля Get All Headers, расположенного на вкладке Transport, данного сервиса равным All:
На этом разработку асинхронного сервиса на OSB можно считать законченной. Протестировать его можно с помощью SOAP UI, предварительно создав там эмулятор сервиса обратного вызова. При этом подразумевается, что за OSB стоит некоторая работающая реализация асинхронного сервиса, т.е. сервиса считывающего сообщения из JMS-очереди запросов, обрабатывающего их и помещающего ответы в очередь ответов. При отправке запроса с помощью SOAP UI необходимо правильно заполнить соответствующие поля на вкладке WS-Addressing related settings, особенно поле Reply To.
Если все в порядке, то после отправки запроса на OSB, в окошке эмулятора сервиса обратного вызова появится ответ.
Текст ответа при этом будет содержать все необходимые поля WS-Addressing, позволяющие произвести его корреляцию с отправленным запросом.
Понравилось сообщение - подпишитесь на блог и Twitter
Сохранить во внешней памяти URL сервиса обратного вызова, т.е. того сервиса, на который нам необходимо отправить асинхронный ответ после завершения работы, и идентификатор поступившего сообщения можно несколькими способами. Один из них - использовать между OSB и реализацией сервиса JMS-очередь и выставить соответствующие дополнительные свойства записываемому в нее сообщению. Аналогично для передачи ответа от реализации сервиса к OSB использовать другую JMS-очередь - очередь ответов. Соответственно, на шине должны присутствовать прокси-сервис, принимающий запрос по протоколу HTTP, извлекающий из его заголовка URL сервиса обратного вызова и идентификатор сообщения и помещающий данный запрос в очередь запросов, а так же прокси-сервис, слушающий очередь ответов и формирующий сообщение для сервиса обратного вызова. При этом в данный прокси-сервис необходимо каким-то образом передать сохраненные в первой очереди - очереди запросов - URL сервиса обратного вызова и идентификатор сообщения-запроса. Сделать это можно с помощью тех же дополнительных свойств JMS-сообщения, помещаемого реализацией сервиса в очередь ответов. Получается, что данная схема накладывает одно ограничение на реализацию сервиса - та должна перекладывать значения дополнительных свойств JMS-сообщения запроса в JMS-сообщение ответа.
Логика первого прокси-сервиса - AsyncProxyService проста. Данный прокси-сервис с помощью HTTP-транспорта принимает SOAP-запросы. Затем принятое сообщение с помощью бизнес-сервиса WriteRequestBusinessService помещается в соответствующую JMS-очередь.
Наиболее интересная задача, решаемая данным прокси-сервисов - формирование дополнительных свойств JMS-сообщения: MessageId - идентификатор принятого сообщения-запроса и Address - URL сервиса обратного вызова. Данные свойства формируются с помощью действия Transport Header.
Извлекаются значения данных свойств из соответствующих полей заголовка SOAP-сообщения: MessageId из поля MessageID:
- $header/wsa05:MessageID/text()
а Address - из поля ReplyTo/Address:
- $header/wsa05:ReplyTo/wsa05:Address/text()
В приведенных выражениях префикс wsa05 соответствует пространству имен http://www.w3.org/2005/08/addressing.
Рассмотрим пример:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:asy="http://www.example.org/AsyncService/">
<soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Action>http://www.example.org/AsyncService/AsyncService/demoOperationRequest</wsa:Action>
<wsa:ReplyTo>
<wsa:Address>http://localhost:8088/mockAsyncServiceCallbackBinding</wsa:Address>
</wsa:ReplyTo>
<wsa:MessageID>uuid:8192b9b4-e268-4f65-a9e8-c1e798eb706f</wsa:MessageID>
</soapenv:Header>
<soapenv:Body>
<asy:demoOperation>
<asy:id>120</asy:id>
<asy:name>Demo</asy:name>
<asy:action>Log</asy:action>
</asy:demoOperation>
</soapenv:Body>
</soapenv:Envelope>
<soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Action>http://www.example.org/AsyncService/AsyncService/demoOperationRequest</wsa:Action>
<wsa:ReplyTo>
<wsa:Address>http://localhost:8088/mockAsyncServiceCallbackBinding</wsa:Address>
</wsa:ReplyTo>
<wsa:MessageID>uuid:8192b9b4-e268-4f65-a9e8-c1e798eb706f</wsa:MessageID>
</soapenv:Header>
<soapenv:Body>
<asy:demoOperation>
<asy:id>120</asy:id>
<asy:name>Demo</asy:name>
<asy:action>Log</asy:action>
</asy:demoOperation>
</soapenv:Body>
</soapenv:Envelope>
При получении данного запроса прокси-сервис AsyncProxyService сформирует следующее JMS-сообщение:
Для чтения JMS-очереди ответов и формирования обратного вызова используется прокси-сервис AsyncCallbackProxyService. Данный прокси-сервис формирует соответствующие стандарту WS-Addressing поля заголовка SOAP-сообщения и отправляет данное сообщение на указанный в дополнительном свойстве Address JMS-сообщения URL сервиса обратного вызова.
Формирование заголовка SOAP-сообщения осуществляется с помощью действия Replace. Необходимо сформировать заголовок, содержащий следующие поля:
- MessageID - идентификатор сообщения обратного вызова. Формируется с помощью встроенной в OSB функции fn-bea:uuid().
- RelatesTo - идентификатор сообщения, на которое отвечает данное. Извлекается из дополнительного заголовка MessageId: {data($inbound/ctx:transport/ctx:request/tp:headers/tp:user-header[@name='MessageId']/@value)}.
- ReplyTo/Address - адрес сервиса для ответа на сообщение обратного вызова. Если продолжение диалога не предусмотрено, то можно указать анонимный адрес: http://www.w3.org/2005/08/addressing/anonymous.
Целиком выражение для формирования заголовка будет выглядеть следующим образом:
<soap-env:Header>
<wsa05:MessageID>{fn:concat('uuid:', fn-bea:uuid())}</wsa05:MessageID>
<wsa05:RelatesTo>{data($inbound/ctx:transport/ctx:request/tp:headers/tp:user-header[@name='MessageId']/@value)}</wsa05:RelatesTo>
<wsa05:ReplyTo>
<wsa05:Address>http://www.w3.org/2005/08/addressing/anonymous</wsa05:Address>
</wsa05:ReplyTo>
</soap-env:Header>
<wsa05:MessageID>{fn:concat('uuid:', fn-bea:uuid())}</wsa05:MessageID>
<wsa05:RelatesTo>{data($inbound/ctx:transport/ctx:request/tp:headers/tp:user-header[@name='MessageId']/@value)}</wsa05:RelatesTo>
<wsa05:ReplyTo>
<wsa05:Address>http://www.w3.org/2005/08/addressing/anonymous</wsa05:Address>
</wsa05:ReplyTo>
</soap-env:Header>
Для отправки ответа по адресу, сохраненному в поле Address, используется действие Routing Options. Данное действие позволяет изменять адрес, на который отправляется ответ, параметры участия сервиса в транзакции (Quality of Service, QoS), режим обмена (Request или Request-Response), интервал между повторами и количество повторов в случае сбоя, а так же приоритет сообщения.
В данном случае нам необходимо изменить параметр URI, подставив в него значение поля Address, получить которое можно с помощью следующего выражения:
$inbound/ctx:transport/ctx:request/tp:headers/tp:user-header[@name='Address']/@value
При этом очень важно помнить, чтобы дополнительные свойства JMS-сообщения были доступны в прокси-сервисе, необходимо выставить значение поля Get All Headers, расположенного на вкладке Transport, данного сервиса равным All:
На этом разработку асинхронного сервиса на OSB можно считать законченной. Протестировать его можно с помощью SOAP UI, предварительно создав там эмулятор сервиса обратного вызова. При этом подразумевается, что за OSB стоит некоторая работающая реализация асинхронного сервиса, т.е. сервиса считывающего сообщения из JMS-очереди запросов, обрабатывающего их и помещающего ответы в очередь ответов. При отправке запроса с помощью SOAP UI необходимо правильно заполнить соответствующие поля на вкладке WS-Addressing related settings, особенно поле Reply To.
Если все в порядке, то после отправки запроса на OSB, в окошке эмулятора сервиса обратного вызова появится ответ.
Текст ответа при этом будет содержать все необходимые поля WS-Addressing, позволяющие произвести его корреляцию с отправленным запросом.
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<add:MessageID xmlns:add="http://www.w3.org/2005/08/addressing">uuid:975eb75b-9604-4762-ba25-e3326b97d619</add:MessageID>
<add:RelatesTo xmlns:add="http://www.w3.org/2005/08/addressing">uuid:7676da44-b1c4-47d5-ba5b-f476a335bf86</add:RelatesTo>
<add:ReplyTo xmlns:add="http://www.w3.org/2005/08/addressing">
<add:Address>http://www.w3.org/2005/08/addressing/anonymous</add:Address>
</add:ReplyTo>
</soapenv:Header>
<soapenv:Body xmlns:asy="http://www.example.org/AsyncService/">
<asy:demoOperationResponse>
<asy:result>true</asy:result>
</asy:demoOperationResponse>
</soapenv:Body>
</soapenv:Envelope>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<add:MessageID xmlns:add="http://www.w3.org/2005/08/addressing">uuid:975eb75b-9604-4762-ba25-e3326b97d619</add:MessageID>
<add:RelatesTo xmlns:add="http://www.w3.org/2005/08/addressing">uuid:7676da44-b1c4-47d5-ba5b-f476a335bf86</add:RelatesTo>
<add:ReplyTo xmlns:add="http://www.w3.org/2005/08/addressing">
<add:Address>http://www.w3.org/2005/08/addressing/anonymous</add:Address>
</add:ReplyTo>
</soapenv:Header>
<soapenv:Body xmlns:asy="http://www.example.org/AsyncService/">
<asy:demoOperationResponse>
<asy:result>true</asy:result>
</asy:demoOperationResponse>
</soapenv:Body>
</soapenv:Envelope>
Понравилось сообщение - подпишитесь на блог и Twitter
Комментариев нет:
Отправить комментарий
Любой Ваш комментарий важен для меня, однако, помните, что действует предмодерация. Давайте уважать друг друга!