Даже если вы полностью удовлетворены работой с устоявшимся стандартом WSDL 1.1, стоит потратить время на то, чтобы узнать, как и почему некоторые функции и элементы языка изменились и расширились с помощью WSDL 2.0. В этой статье мы начнем фокусироваться на различиях между WSDL 1.1 и 2.0, а затем перейдем к сборке всего документа WSDL 2.0. Обратите внимание, что эта статья не является введением в язык описания веб-служб. Если вы новичок в WSDL, то перед продолжением ознакомьтесь с основными элементами WSDL 1.1.
Эта статья написана Кевином Лю и опубликована в журнале SOA в феврале 2009 года.
Введение
Как показано на рисунке, язык WSDL 2.0 вносит некоторые заметные различия в структуру документа определения WSDL, а именно:
• | Элемент определений переименован в описание . |
• | Элемент portType переименован в interface . |
• | Элемент порта переименован в конечную точку . |
Кроме того, элемент сообщения удаляется, как описано в следующем разделе.
Рисунок 1: WSDL 2.0 наследует свою общую структуру от WSDL 1.1, но вносит некоторые изменения как в абстрактные, так и в конкретные описания. |
Устранение сообщений Элемент
WSDL — 1.1 сообщений элемента , в основном , предназначены для использования в качестве моста между Сообщение- и RPC-ориентированной коммуникации. Его можно использовать для описания сообщения типа документа на основе только одного элемента детали или он может поддерживать сообщения типа RPC (управляемые параметрами) на основе нескольких частей. Однако его выразительная сила для RPC ограничена. Например, он не может описывать переменное количество входных параметров или выбор ответов. WSDL 2.0 устраняет этот сдвиг в отрасли, полностью исключая поддержку элемента сообщения . Он просто позволяет операции ссылаться на тип (например, элемент схемы XML) напрямую.
Определение интерфейса
WSDL 2.0 не только изменяет имя элемента определения интерфейса с portType на interface, но также расширяет конструкцию интерфейса набором новых элементов и атрибутов, как показано в выделенных частях этого примера:
<interface name="..." extends="..." styleDefault="...">
<fault name="..." element="..." />
<operation name="..." pattern="..." style="..."
wsdlx:safe="...">
<input messageLabel="..." element="..." />
<output messageLabel="..." element="..." />
<infault ref="..." messageLabel="..." />
<outfault ref="..." messageLabel="..." />
</operation>
</interface>
Давайте рассмотрим эти новые элементы и атрибуты более подробно. Интерфейс элемент расширяет Атрибут объектно-ориентированное программирование было введено понятие наследования интерфейса , посредством которого нового интерфейс может быть получен из существующего интерфейса путем наследования , а затем расширяя свои операции. Необязательный атрибут extends элемента интерфейса позволяет одному интерфейсу расширять или наследовать от одного или нескольких других интерфейсов. В таких случаях интерфейс содержит все операции, которые он расширяет, плюс операции, которые он определяет напрямую. Теперь давайте посмотрим на пример того, как работает атрибут extends .
ActionCon вводит требование о том, что любые действия, связанные с обработкой заказов на покупку, должны регистрироваться в центре хранения для целей аудита. Как показано здесь, Стив определяет интерфейс для ведения журнала, а затем использует этот интерфейс в одном из нескольких интерфейсов, связанных с заказами на покупку.
<interface name="ifPurchaseOrderLog">
<operation name="opLogOrder"
pattern="http://www.w3.org/2006/01/wsdl/out-only">
<output messageLabel="Out" element="po:orderLog"/>
</operation>
</interface>
IfPurchaseOrderLog интерфейс конструкция представляет собой операцию , которая может быть унаследована другими конструкциями интерфейса и ifPurchaseOrder интерфейса конструкции представляет собой интерфейс , который наследует его с помощью использования из простирается атрибут.
<interface name="ifPurchaseOrder" extends="tns:ifPurchaseOrderLog" >
<operation name="opChangeOrder"
pattern="http://www.w3.org/2006/01/wsdl/in-out">
<input messageLabel="In" element="po:purchaseOrder "/>
<output messageLabel="Out" element="po:acknowledgement"/>
</operation>
<operation name="opCancelOrder"
pattern="http://www.w3.org/2006/01/wsdl/in-out">
<input messageLabel="In" element="po:poNumber"/>
<output messageLabel="Out" element="po:acknowledgement"/>
</operation>
</interface>
В результате наследования интерфейс ifPurchaseOrder теперь содержит три операции: opLogOrder, opChangeOrder и opCancelOrder.
В интерфейсном элементе styleDefault атрибутов
Стили определяют определенные правила, которые применяются к операциям. StyleDefault атрибут может быть использован для установки значения по умолчанию для стиля атрибутов всех операций по интерфейсу.
<interface name="ifPurchaseOrderLog"
styleDefault="http://www.w3.org/ns/wsdl/style/iri">
<operation name="opLogOrder"
pattern="http://www.w3.org/2006/01/wsdl/out-only">
<output messageLabel="Out" element="po:orderLog"/>
</operation>
</interface>
Предоставляются следующие предопределенные значения стиля:
• | Стиль RPC (http://www.w3.org/ns/wsdl/style/rpc) Требует, чтобы все операции в интерфейсе должны соответствовать правилам для сообщений в стиле RPC. |
• | Стиль IRI (http://www.w3.org/ns/wsdl/style/iri) Ограничивает определения сообщений, чтобы их можно было сериализовать в нечто вроде HTTP-кодирования URL. |
• | Multipart (http://www.w3.org/ns/wsdl/style/multipart) В привязке HTTP для клиентов XForms сообщение должно быть определено в соответствии с этим стилем и сериализовано как «Multipart / form-data». |
Точные правила и ограничения каждого стиля описаны в спецификации WSDL 2.0.
Элементы операции могут иметь индивидуальные
настройки атрибутов стиля , которые переопределяют
настройку styleDefault родительского
элемента интерфейса .
StyleDefault атрибут является необязательным; если он отсутствует, это просто означает, что не нужно соблюдать никаких дополнительных правил.
Wsdlx: сейф Global Атрибут Этот новый атрибут указывает, считается ли операция быть «безопасными» в соответствии со спецификацией W3C Web Architecture, которая гласит:
«… Безопасное взаимодействие — это такое, когда агент не берет на себя никаких обязательств помимо взаимодействия. Агент может брать на себя обязательства другими способами (например, путем подписания контракта). Если агент не имеет обязательства перед безопасным взаимодействием, впоследствии у него нет этого обязательства.
Другие веб-взаимодействия напоминают заказы больше, чем запросы. Эти небезопасные взаимодействия могут вызвать изменение состояния ресурса, и пользователь может нести ответственность за последствия этих взаимодействий. Небезопасные взаимодействия включают подписку на новостная рассылка, публикация в списке или изменение базы данных. Примечание. В этом контексте слово «небезопасный» не обязательно означает «опасный»… ».
Другими словами, если операция выполняет что-то вроде функции «только для чтения», которая не изменяет навсегда какую-либо часть среды обслуживания, или если она не дает потребителю никаких новых обязательств, то она считается «безопасной».
Этот атрибут по сути является средством, с помощью которого контракт на обслуживание может сообщать о том, что с конкретной операцией связан небольшой риск. Это может быть полезно, особенно в поддержку принципа обнаружения услуг, который побуждает нас улучшать качество связи по контракту. Тем не менее, также необходимо принимать во внимание аспекты абстракции сервиса. В некоторых случаях может быть сочтено необходимым вообще не разрешать этот атрибут.
Если это разрешено, важно, чтобы существовали процедуры управления SOA для управления потенциальным изменением этого параметра. Если потребительские программы становятся зависимыми от операции службы с предположением, что она безопасна, а затем базовая функциональность операции изменяется так, что она больше не считается безопасной, то это может иметь различные негативные последствия. Может также потребоваться, чтобы этот параметр был программно получен определенными потребителями.
Значением по умолчанию
атрибута wsdlx: safe является «false». Следовательно, если атрибут отсутствует или явно задан как false, потребитель может предположить, что операция «небезопасна».
В разломах , infault и outfault элементов
В WSDL 2.0
элемент fault повышается до дочернего элемента первого уровня в
конструкции интерфейса . Это поднимает
ошибку на тот же уровень, что и операция, позволяя повторно использовать одно сообщение об ошибке в разных операциях.
Как показано в этом примере, на отказ можно ссылаться несколькими операциями через
атрибуты ref их
элементов infault и
outfault .
<types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://actioncon.com/schema/po"
targetNamespace="http://actioncon.com/schema/po"
elementFormDefault="qualified">
<xsd:element name="invalidOrder"
type="invalidOrderType"/>
<xsd:complexType name="invalidOrderType">
<xsd:sequence>
<xsd:element name="PODate" type="xsd:date"/>
<xsd:element name="OrderID" type="xsd:string"/>
<xsd:element name="Desc" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</types>
Эта
конструкция типов определяет
тип invalidOrderType, который впоследствии повторно используется как сообщение об
ошибке операциями opChangeOrder и
opCancelOrder через их соответствующие
элементы outfault .
<interface name="ifPurchaseOrder" extends="tns:ifPurchaseOrderLog" >
<fault name="invalidOrderFault" element="po:invalidOrder"/>
<operation name="opChangeOrder"
pattern="http://www.w3.org/2006/01/wsdl/in-out">
<input messageLabel="In" element="po:purchaseOrder "/>
<output messageLabel="Out" element="po:acknowledgement"/>
<outfault ref="tns:invalidOrderFault" messageLabel="Out/>
</operation>
<operation name="opCancelOrder"
pattern="http://www.w3.org/2006/01/wsdl/in-out">
<input messageLabel="In" element="po:poNumber"/>
<output messageLabel="Out"
element="po:acknowledgement"/>
<outfault ref="tns:invalidOrderFault" messageLabel="Out/>
</operation>
</interface>
Определение ошибок на уровне интерфейса особенно полезно для определений привязки. Например, ошибка SOAP может иметь код ошибки (и субкоды) в дополнение к деталям сообщения об ошибке. Определяя ошибки на уровне интерфейса, вы можете гарантировать, что общие коды ошибок могут использоваться во всех операциях, которые используют ошибки.
Например, когда интерфейс в следующем примере привязан к SOAP 1.2, можно указать код ошибки SOAP в качестве «отправителя» для всех ошибок недопустимого заказа.
<binding name="bdPurchaseOrder-SOAP12HTTP"
interface="tns:ifPurchaseOrder" >
<fault ref="tns:invalidOrderFault" soap12:code="soap12:Sender"/>
<operation ref="tns:opChangeOrder" .../>
<operation ref="tns:opCancelOrder" .../>
</binding>
В этом примере
элемент сбоя связан с
элементом привязки и поэтому становится применимым к обеим операциям в определении привязки, позволяя операциям повторно использовать один и тот же код ошибки.
Учитывая структуру интерфейса и определения привязки, во время выполнения, если обнаружен неправильный порядок, возвращаемое отправителю сообщение об ошибке будет выглядеть примерно так:
<soap:Envelope xmlns:soap=
"http://www.w3.org/2003/05/soap-envelope"
xmlns:po="http://actioncon.com/schema/po" ...>
<soap:Body>
<soap:Fault>
<soap:Code>
<soap:Value>soap:Sender</soap:Value>
</soap:Code>
<soap:Detail>
<po:invalidOrder>
<po:PODate>02-23-2008</po:PODate>
<po:OrderID>1234</po:OrderID>
<po:Desc>
The required order party ID is missing.
</po:Desc>
</po:invalidOrder>
</soap:Detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>
Модели и messageLabel Атрибуты
The WSDL 2.0 спецификация позволяет модели обмена сообщениями (Meps) должны быть определены в отдельных спецификациях , а затем привел в
операции определения с помощью нового
шаблона атрибута.
Спецификация Areated MEP устанавливает, сколько сообщений обменивается и в каком порядке. Каждое сообщение может быть идентифицировано с помощью метки сообщения и направления («в» или «вне»).
Операция, в которой используется конкретный MEP, должна предоставлять соответствующее количество сообщений на основе следующих правил:
• | Для каждого сообщения с направлением «In» элемент ввода должен быть определен с атрибутом messageLabel, установленным в «In». |
• | Для каждого сообщения с направлением «Out» выходной элемент определяется с атрибутом messageLabel, установленным в «Out». |
• | Порядок элементов ввода и вывода должен быть таким же, как порядок их соответствующих сообщений, определенных в спецификации MEP. |
WSDL2.0 использует новые термины для описания MEP. Например, MEP «Запрос-Ответ» из WSDL 1.1 теперь называется «In-Out», а MEP «One-Way» был переименован в «In».
MessageLabel атрибут ввода, вывода, или иной операции
замыкания элемента просто указывает на роль , которую играет в сообщении MEP. Например, установка
message-Label = «In» для MEP «In-Out» означает, что сообщение является входным сообщением операции «In-Out». (Это может показаться излишним, поскольку имя
входного элемента уже указывает, что это входное сообщение.)
Вот пример, в котором используются
pattern и
messageLabel
атрибуты для операции на основе MEP «In-Out».
<operation name="opChangeOrder"
pattern="http://www.w3.org/2006/01/wsdl/in-out">
<input messageLabel="In" element="po:purchaseOrder "/>
<output messageLabel="Out" element="po:acknowledgement"/>
</operation>
Определения службы и конечной точки
В WSDL 2.0
элемент службы может реализовывать только один интерфейс через свой
атрибут интерфейса, как показано в следующем примере. Это означает, что когда служба имеет более одного
элемента конечной точки , они используют общий
интерфейс, но используют разные привязки и адреса.
Это потому, что они являются альтернативами в том смысле, что каждая конечная точка может обеспечивать одинаковое поведение через разные конфигурации привязки. Позволяя сервисам предоставлять альтернативные конечные точки, потребители имеют больше свободы в определении того, какой порт является лучшим для данной цели.
<service name="svPurchaseOrder" interface="ifPurchaseOrder">
<endpoint name="purchaseOrder-http-soap12"
binding="tns:bdPO-SOAP12HTTP" address=
"http://actioncon.com/services/soap12/purchaseOrder"/>
</service>
Полное определение WSDL 2.0
В следующем примере кода показано полное определение WSDL 2.0. Выделенные разделы указывают, где язык WSDL 2.0 отличается от WSDL 1.1.
<descriptiontargetNamespace="http://actioncon.com/contract/po"
xmlns="8http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://actioncon.com/contract/po"
xmlns:po="http://actioncon.com/schema/po"
xmlns:soapbind="http://www.w3.org/ns/wsdl/soap">
<!- BEGIN ABSTRACT DESCRIPTION ->
<types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://actioncon.com/schema/po"
targetNamespace="http://actioncon.com/schema/po"
elementFormDefault="qualified">
<xsd:element name="purchaseOrder" type="PurchaseOrderType"/>
<xsd:element name="acknowledgement" type="xsd:string"/>
<xsd:element name="poNumber" type="xsd:integer"/>
<xsd:element name="status" type="xsd:string"/>
<xsd:complexType name="PurchaseOrderType">
<xsd:sequence>
<xsd:element ref="poNumber"/>
<xsd:element name="PODate" type="xsd:date"/>
<xsd:element name="BillToParty" type="PartyType"/>
<xsd:element name="ShipToParty" type="PartyType"/>
<xsd:element name="LineItems" type="LineItemsType"/>
</xsd:sequence>
<xsd:attribute name="version" type="xsd:decimal"/>
</xsd:complexType>
<xsd:complexType name="PartyType">
<xsd:sequence>
<xsd:element name="ID" type="xsd:integer"/>
<xsd:element name="PartyName" type="xsd:string"/>
<xsd:element name="ContactName" type="xsd:string"/>
<xsd:element name="Phone" type="xsd:string"/>
<xsd:element name="Address" type="AddressType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AddressType">
<xsd:sequence>
<xsd:element name="Line1" type="xsd:string"/>
<xsd:element name="Line2" type="xsd:string"
minOccurs="0"/>
<xsd:element name="City" type="xsd:string"/>
<xsd:element name="State" type="xsd:string"/>
<xsd:element name="PostalCode" type="xsd:string"/>
<xsd:element name="Country" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LineItemsType">
<xsd:sequence>
<xsd:element name="LineItem" type="LineItemType"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LineItemType">
<xsd:sequence>
<xsd:element name="ProductID" type="ProductIDType"/>
<xsd:element name="ProductName" type="xsd:string"/>
<xsd:element name="Quantity" type="xsd:int"/>
<xsd:element name="Price" type="PriceType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:simpleType name="ProductIDType">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[A-Z]{2}[0-9]{4}"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="PriceType">
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="8"/>
<xsd:fractionDigits value="2"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
</types>
<interface name="ifPurchaseOrder">
<operation name="opSubmitOrder"
pattern="http://www.w3.org/2006/01/wsdl/in-out">
<input messageLabel="In" element="po:purchaseOrder"/>
<output messageLabel="Out" element="po:acknowlegement"/>
</operation>
<operation name="opCheckOrderStatus"
pattern="http://www.w3.org/2006/01/wsdl/in-out">
<input messageLabel="In" element="po:poNumber"/>
<output messageLabel="Out" element="po:status"/>
</operation>
<operation name="opChangeOrder"
pattern="http://www.w3.org/2006/01/wsdl/in-out">
<input messageLabel="In" element="po:purchaseOrder "/>
<output messageLabel="Out" element="po:acknowledgement"/>
</operation>
<operation name="opCancelOrder"
pattern="http://www.w3.org/2006/01/wsdl/in-out">
<input messageLabel="In" element="po:poNumber"/>
<output messageLabel="Out" element="po:acknowledgement"/>
</operation>
</interface>
<!- END ABSTRACT DESCRIPTION ->
<!- BEGIN CONCRETE DESCRIPTION ->
<binding name="bdPO-SOAP12HTTP" interface="ifPurchaseOrder"
type="http://www.w3.org/2006/01/wsdl/soap"
soapbind:protocol=
"http://www.w3.org/2003/05/soap/bindings/HTTP">
<operation ref="tns:opSubmitOrder"
soapbind:mep=
"http://www.w3.org/2003/05/soap/mep/request-response"
soapbind:action=
"http://actioncon.com/submitOrder/request"/>
<operation ref="opCheckOrderStatus"
soapbind:mep=
"http://www.w3.org/2003/05/soap/mep/request-response"
soapbind:action=
"http://actioncon.com/checkOrder/request"/>
<operation ref="opChangeOrder"
soapbind:mep=
"http://www.w3.org/2003/05/soap/mep/request-response"
soapbind:action=
"http://actioncon.com/changeOrder/request"/>
<operation ref="opCancelOrder"
soapbind:mep=
"http://www.w3.org/2003/05/soap/mep/request-response"
soapbind:action=
"http://actioncon.com/cancelOrder/request"/>
</binding>
<service name="svPurchaseOrder" interface="ifPurchaseOrder">
<endpoint name="purchaseOrder-http-soap12"
binding="tns:bdPO-SOAP12HTTP" address=
"http://actioncon.com/services/soap12/purchaseOrder"/>
</service>
<!- END CONCRETE DESCRIPTION ->
</description>
Заключение
WSDL 2.0 вносит некоторые существенные изменения в структуру и язык выражения контрактов на веб-службы. Некоторые из этих изменений могут оказаться полезными, если вы сможете ими воспользоваться, в то время как другие могут быть излишне разрушительными. Лучший подход заключается в том, чтобы получить полное понимание вариантов, а затем принять обоснованное решение.
Ссылки
[REF-1] «Разработка и создание версий контракта веб-сервиса для SOA» Томаса Эрла, Аниша Кармаркара, Присциллы Уолмсли, Хьюго Хааса, Умит Ялкинальп, Каньянга Кевина Лю, Дэвида Орчарда, Андре Тоста, Джеймса Пашли для «Prentice Hall Service» Серия ориентированных вычислений от Томаса Эрла «, Copyright Prentice Hall / Pearson PTR и SOA Systems Inc., http://www.soabooks.com/wsc/
Эта статья была первоначально опубликована в журнале The SOA Magazine ( www.soamag.com ), официально связанном с серией сервис-ориентированных вычислений Prentice Hall от Томаса Эрла ( www.soabooks.com ). Copyright © SOA Systems Inc. ( www.soasystems.com )