Каждый веб-сервис предоставляет документ WSDL (Web Service Description Language - язык описания веб-сервиса), в котором описывается все, что клиенту необходимо для работы с этим сервисом. WSDL-документ предоставляет простой и последовательный способ задания разработчиком синтаксиса вызова любого веб-метода. Более того, этот документ позволяет использовать инструменты автоматического генерирования прокси-классов, подобные включенным в среды Visual Studio .NET и.NET Framework. Благодаря указанным средствам использование веб-сервиса является таким же простым, как и применение локального класса.
WSDL-документ имеет основанный на XML формат, в соответствии с которым информация подразделяется на пять групп. Первые три группы представляют собой абстрактные определения, не зависящие от особенностей платформы, сети или языка, а оставшиеся две группы включают конкретные описания.
Протокол soap
Связь между веб-сервисами и их клиентами осуществляется посредством сообщений в формате XML.
SOAP (Simple Object Access Protocol - простой протокол доступа к объектам) представляет собой протокол сообщений для выбора веб-сервисов.
Основная идея стандарта SOAP заключается в том, что сообщения должны быть закодированы в стандартизированном XML-формате.
Кроме сообщений SOAP, для обмена данными с сервисами.NET можно использовать методы GET и POST протокола HTTP.
Преимущества применения формата SOAP перед другими форматами для передачи данных:
Кодировать в XML структуры данных и наборы DataSet с использованием SOAP так же легко, как и данные простых скалярных типов.
При использовании SOAP-сообщений предоставляются дополнительные инструменты, позволяющие легко добавлять, например, функции обеспечения безопасности или трассировки.
Имеются наборы инструментов SOAP для различных языков программирования (и даже для предыдущих версий Microsoft C++ и Visual Basic). Иначе, для того чтобы обеспечить связь с сервисом посредством методов GET и POST протокола HTTP, придется, очевидно, самостоятельно конструировать строку запроса, а затем проводить синтаксический анализ ответа.
Стандарт disco
Стандарт DISCO предоставляет простейший способ получения доступа к файлам манифестов, позволяющий группировать ссылки на веб-сервисы.
DISCO-файл может включать файлы различных веб-серверов и поддерживает "динамический поиск" - автоматический поиск каталога файлов веб-сервисов на сервере.
Файлы манифеста полезны тем, что объединяют множество веб-сервисов в единственном списке, однако они не позволяют клиентам отыскивать веб-сервисы определенного типа без указания наименования компании-разработчика.
Спецификация uddi
Спецификация UDDI (Universal Description, Discovery, and Integration - универсальное описание, поиск и интеграция) позволяет избежать указанных проблем посредством использования специального хранилища (репозитория), где предприятия и организации могут размещать данные о предоставляемых ими сервисах. Инициаторами создания технологии UDDI стали более 100 компаний (полный список можно найти по адресу http://www.uddi.org/community.html), включая Sun и Microsoft. Объединив свои усилия, эти компании разработали проект спецификации UDDI, которая по истечении 18 месяцев была стандартизирована.
Информация в этом репозитории должна обновляться вручную. С этой целью некоторые "узловые операторы" хранят идентичные копии репозитория UDDI. Эти компании обеспечивают хранение указанного репозитория и бесплатный доступ к нему для популяризации веб-серисов. Кроме того, Майкрософт включила версию UDDI в программное обеспечение сервера Windows .NET для использования в корпоративных сетях интранета.
В хранилище UDDI содержатся сведения о предприятиях, предоставляющих веб-сервисы, о типе каждого сервиса и связях с информацией и спецификациями, относящимися к этим сервисам. Интерфейс UDDI сам по себе представляет собой веб-сервис. Для регистрации или поиска службы следует отправить SOAP-сообщение.
Главными недостатками веб-сервисов являются меньшая производительность и больший размер сетевого трафика по сравнению с такими технологиями как RMI, CORBA, DCOM за счет использования текстовых XML-сообщений.
Заголовок топика – это действительно вопрос, т.к. я сам не знаю, что это и впервые попробую поработать с этим в рамках настоящей статьи. Единственное, что могу гарантировать, что код, представленный ниже, будет работать, однако мои фразы будут лишь предположениями и догадками о том, как я сам все это понимаю. Итак, поехали…
Введение
Начать надо с того, для чего создавалась концепция веб-сервисов. К моменту появления этого понятия в мире уже существовали технологии, позволяющие приложениям взаимодействовать на расстоянии, где одна программа могла вызвать какой-нибудь метод в другой программе, которая при этом могла быть запущена на компьютере, расположенном в другом городе или даже стране. Все этого сокращенно называется RPC (Remote Procedure Calling – удаленный вызов процедур). В качестве примеров можно привести технологии CORBA, а для Java – RMI (Remote Method Invoking – удаленный вызов методов). И все вроде в них хорошо, особенно в CORBA, т.к. с ней можно работать на любом языке программирования, но чего-то все же не хватало. Полагаю, что минусом CORBA является то, что она работает через какие-то свои сетевые протоколы вместо простого HTTP, который пролезет через любой firewall. Идея веб-сервиса заключалась в создании такого RPC, который будет засовываться в HTTP пакеты. Так началась разработка стандарта. Какие у этого стандарта базовые понятия:- SOAP . Прежде чем вызвать удаленную процедуру, нужно этот вызов описать в XML файле формата SOAP. SOAP – это просто одна из многочисленных XML разметок, которая используется в веб-сервисах. Все, что мы хотим куда-то отправить через HTTP, сначала превращается в XML описание SOAP, потом засовывается в HTTP пакет и посылается на другой компьютер в сети по TCP/IP.
- WSDL . Есть веб-сервис, т.е. программа, методы которой можно удаленно вызывать. Но стандарт требует, чтобы к этой программе прилагалось описание, в котором сказано, что «да, вы не ошиблись – это действительно веб-сервис и можно у него вызвать такие-то такие-то методы». Такое описание представляется еще одним файлом XML, который имеет другой формат, а именно WSDL. Т.е. WSDL – это просто XML файл описания веб-сервиса и больше ничего.
Общий подход
В веб-сервисах всегда есть клиент и сервер. Сервер – это и есть наш веб-сервис и иногда его называют endpoint (типа как, конечная точка, куда доходят SOAP сообщения от клиента). Нам нужно сделать следующее:- Описать интерфейс нашего веб-сервиса
- Реализовать этот интерфейс
- Запустить наш веб-сервис
- Написать клиента и удаленно вызвать нужный метод веб-сервиса
Сервер
Запустим IDEA и создадим новый проект Create New Project . Укажем имя HelloWebService и нажмем кнопку Next , далее кнопку Finish . В папке src создадим пакет ru.javarush.ws . В этом пакете создадим интерфейс HelloWebService: package ru. javarush. ws; // это аннотации, т.е. способ отметить наши классы и методы, // как связанные с веб-сервисной технологией import javax. jws. WebMethod; import javax. jws. WebService; import javax. jws. soap. SOAPBinding; // говорим, что наш интерфейс будет работать как веб-сервис @WebService // говорим, что веб-сервис будет использоваться для вызова методов @SOAPBinding (style = SOAPBinding. Style. RPC) public interface HelloWebService { // говорим, что этот метод можно вызывать удаленно @WebMethod public String getHelloString (String name) ; } В этом коде классы WebService и WebMethod являются так называемыми аннотациям и ничего не делают, кроме как помечают наш интерфейс и его метод, как веб-сервис. Это же относится и к классу SOAPBinding . Разница лишь в том, что SOAPBinding – это аннотация с параметрами. В данном случае используется параметр style со значением, говорящим, что веб-сервис будет работать не через сообщения-документы, а как классический RPC, т.е. для вызова метода. Давайте реализуем логику нашего интерфейса и создадим в нашем пакете класс HelloWebServiceImpl . Кстати, замечу, что окончание класса на Impl – это соглашение в Java, по которому так обозначают реализацию интерфейсов (Impl – от слова implementation, т.е. реализация). Это не требование и вы вольны назвать класс как хотите, но правила хорошего тона того требуют: package ru. javarush. ws; // таже аннотация, что и при описании интерфейса, import javax. jws. WebService; // но здесь используется с параметром endpointInterface, // указывающим полное имя класса интерфейса нашего веб-сервиса @WebService (endpointInterface = "ru.javarush.ws.HelloWebService" ) public class HelloWebServiceImpl implements HelloWebService { @Override public String getHelloString (String name) { // просто возвращаем приветствие return "Hello, " + name + "!" ; } } Запустим наш веб-сервис как самостоятельный сервер, т.е. без участия всяких Tomcat и серверов приложений (это тема отдельного разговора). Для этого в структуре проекта в папке src создадим пакет ru.javarush.endpoint , а в нем создадим класс HelloWebServicePublisher с методом main: package ru. javarush. endpoint; // класс, для запуска веб-сервера с веб-сервисами import javax. xml. ws. Endpoint; // класс нашего веб-сервиса import ru. javarush. ws. HelloWebServiceImpl; public class HelloWebServicePublisher { public static void main (String. . . args) { // запускаем веб-сервер на порту 1986 // и по адресу, указанному в первом аргументе, // запускаем веб-сервис, передаваемый во втором аргументе Endpoint. publish ("http://localhost:1986/wss/hello" , new HelloWebServiceImpl () ) ; } } Теперь запустим этот класс, нажав Shift+F10 . В консоли ничего не появится, но сервер запущен. В этом можно убедиться набрав в браузере строку http://localhost:1986/wss/hello?wsdl . Открывшаяся страница, с одной стороны, доказывает, что у нас на компьютере (localhost) запустился веб-сервер (http://) на порту 1986, а, с другой стороны, показывает WSDL описание нашего веб-сервиса. Если вы остановите приложение, то описание станет недоступно, как и сам веб-сервис, поэтому делать этого не будем, а перейдем к написанию клиента.Клиент
В папке проекта src создадим пакет ru.javarush.client , а в нем класс HelloWebServiceClient с методом main: package ru. javarush. client; // нужно, чтобы получить wsdl описание и через него // дотянуться до самого веб-сервиса import java. net. URL; // такой эксепшн возникнет при работе с объектом URL import java. net. MalformedURLException; // классы, чтобы пропарсить xml-ку c wsdl описанием // и дотянуться до тега service в нем import javax. xml. namespace. QName; import javax. xml. ws. Service; // интерфейс нашего веб-сервиса (нам больше и нужно) import ru. javarush. ws. HelloWebService; public class HelloWebServiceClient { public static void main (String args) throws MalformedURLException { // создаем ссылку на wsdl описание URL url = new URL ("http://localhost:1986/wss/hello?wsdl" ) ; // Параметры следующего конструктора смотрим в самом первом теге WSDL описания - definitions // 1-ый аргумент смотрим в атрибуте targetNamespace // 2-ой аргумент смотрим в атрибуте name QName qname = new QName ("http://ws.javarush.ru/" , "HelloWebServiceImplService" ) ; // Теперь мы можем дотянуться до тега service в wsdl описании, Service service = Service. create (url, qname) ; // а далее и до вложенного в него тега port, чтобы // получить ссылку на удаленный от нас объект веб-сервиса HelloWebService hello = service. getPort (HelloWebService. class ) ; // Ура! Теперь можно вызывать удаленный метод System. out. println (hello. getHelloString ("JavaRush" ) ) ; } } Максимум комментариев по коду я дал в листинге. Добавить мне нечего, поэтому запускаем (Shift+F10). Мы должны в консоли увидеть текст: Hello, JavaRush! Если не увидели, то видимо забыли запустить веб-сервис.Заключение
В данном топике был представлен краткий экскурс в веб-сервисы. Еще раз скажу, что многое из того, что я написал – это мои догадки по поводу того, как это работает, и поэтому мне не стоит сильно доверять. Буду признателен, если знающие люди меня поправят, ведь тогда я чему-нибудь научусь. UPD.Заголовок топика – это действительно вопрос, т.к. я сам не знаю, что это и впервые попробую поработать с этим в рамках настоящей статьи. Единственное, что могу гарантировать, что код, представленный ниже, будет работать, однако мои фразы будут лишь предположениями и догадками о том, как я сам все это понимаю. Итак, поехали…
Введение
Начать надо с того, для чего создавалась концепция веб-сервисов. К моменту появления этого понятия в мире уже существовали технологии, позволяющие приложениям взаимодействовать на расстоянии, где одна программа могла вызвать какой-нибудь метод в другой программе, которая при этом могла быть запущена на компьютере, расположенном в другом городе или даже стране. Все этого сокращенно называется RPC (Remote Procedure Calling – удаленный вызов процедур). В качестве примеров можно привести технологии CORBA, а для Java – RMI (Remote Method Invoking – удаленный вызов методов). И все вроде в них хорошо, особенно в CORBA, т.к. с ней можно работать на любом языке программирования, но чего-то все же не хватало. Полагаю, что минусом CORBA является то, что она работает через какие-то свои сетевые протоколы вместо простого HTTP, который пролезет через любой firewall. Идея веб-сервиса заключалась в создании такого RPC, который будет засовываться в HTTP пакеты. Так началась разработка стандарта. Какие у этого стандарта базовые понятия:- SOAP . Прежде чем вызвать удаленную процедуру, нужно этот вызов описать в XML файле формата SOAP. SOAP – это просто одна из многочисленных XML разметок, которая используется в веб-сервисах. Все, что мы хотим куда-то отправить через HTTP, сначала превращается в XML описание SOAP, потом засовывается в HTTP пакет и посылается на другой компьютер в сети по TCP/IP.
- WSDL . Есть веб-сервис, т.е. программа, методы которой можно удаленно вызывать. Но стандарт требует, чтобы к этой программе прилагалось описание, в котором сказано, что «да, вы не ошиблись – это действительно веб-сервис и можно у него вызвать такие-то такие-то методы». Такое описание представляется еще одним файлом XML, который имеет другой формат, а именно WSDL. Т.е. WSDL – это просто XML файл описания веб-сервиса и больше ничего.
Общий подход
В веб-сервисах всегда есть клиент и сервер. Сервер – это и есть наш веб-сервис и иногда его называют endpoint (типа как, конечная точка, куда доходят SOAP сообщения от клиента). Нам нужно сделать следующее:- Описать интерфейс нашего веб-сервиса
- Реализовать этот интерфейс
- Запустить наш веб-сервис
- Написать клиента и удаленно вызвать нужный метод веб-сервиса
Сервер
Запустим IDEA и создадим новый проект Create New Project . Укажем имя HelloWebService и нажмем кнопку Next , далее кнопку Finish . В папке src создадим пакет ru.javarush.ws . В этом пакете создадим интерфейс HelloWebService: package ru. javarush. ws; // это аннотации, т.е. способ отметить наши классы и методы, // как связанные с веб-сервисной технологией import javax. jws. WebMethod; import javax. jws. WebService; import javax. jws. soap. SOAPBinding; // говорим, что наш интерфейс будет работать как веб-сервис @WebService // говорим, что веб-сервис будет использоваться для вызова методов @SOAPBinding (style = SOAPBinding. Style. RPC) public interface HelloWebService { // говорим, что этот метод можно вызывать удаленно @WebMethod public String getHelloString (String name) ; } В этом коде классы WebService и WebMethod являются так называемыми аннотациям и ничего не делают, кроме как помечают наш интерфейс и его метод, как веб-сервис. Это же относится и к классу SOAPBinding . Разница лишь в том, что SOAPBinding – это аннотация с параметрами. В данном случае используется параметр style со значением, говорящим, что веб-сервис будет работать не через сообщения-документы, а как классический RPC, т.е. для вызова метода. Давайте реализуем логику нашего интерфейса и создадим в нашем пакете класс HelloWebServiceImpl . Кстати, замечу, что окончание класса на Impl – это соглашение в Java, по которому так обозначают реализацию интерфейсов (Impl – от слова implementation, т.е. реализация). Это не требование и вы вольны назвать класс как хотите, но правила хорошего тона того требуют: package ru. javarush. ws; // таже аннотация, что и при описании интерфейса, import javax. jws. WebService; // но здесь используется с параметром endpointInterface, // указывающим полное имя класса интерфейса нашего веб-сервиса @WebService (endpointInterface = "ru.javarush.ws.HelloWebService" ) public class HelloWebServiceImpl implements HelloWebService { @Override public String getHelloString (String name) { // просто возвращаем приветствие return "Hello, " + name + "!" ; } } Запустим наш веб-сервис как самостоятельный сервер, т.е. без участия всяких Tomcat и серверов приложений (это тема отдельного разговора). Для этого в структуре проекта в папке src создадим пакет ru.javarush.endpoint , а в нем создадим класс HelloWebServicePublisher с методом main: package ru. javarush. endpoint; // класс, для запуска веб-сервера с веб-сервисами import javax. xml. ws. Endpoint; // класс нашего веб-сервиса import ru. javarush. ws. HelloWebServiceImpl; public class HelloWebServicePublisher { public static void main (String. . . args) { // запускаем веб-сервер на порту 1986 // и по адресу, указанному в первом аргументе, // запускаем веб-сервис, передаваемый во втором аргументе Endpoint. publish ("http://localhost:1986/wss/hello" , new HelloWebServiceImpl () ) ; } } Теперь запустим этот класс, нажав Shift+F10 . В консоли ничего не появится, но сервер запущен. В этом можно убедиться набрав в браузере строку http://localhost:1986/wss/hello?wsdl . Открывшаяся страница, с одной стороны, доказывает, что у нас на компьютере (localhost) запустился веб-сервер (http://) на порту 1986, а, с другой стороны, показывает WSDL описание нашего веб-сервиса. Если вы остановите приложение, то описание станет недоступно, как и сам веб-сервис, поэтому делать этого не будем, а перейдем к написанию клиента.Клиент
В папке проекта src создадим пакет ru.javarush.client , а в нем класс HelloWebServiceClient с методом main: package ru. javarush. client; // нужно, чтобы получить wsdl описание и через него // дотянуться до самого веб-сервиса import java. net. URL; // такой эксепшн возникнет при работе с объектом URL import java. net. MalformedURLException; // классы, чтобы пропарсить xml-ку c wsdl описанием // и дотянуться до тега service в нем import javax. xml. namespace. QName; import javax. xml. ws. Service; // интерфейс нашего веб-сервиса (нам больше и нужно) import ru. javarush. ws. HelloWebService; public class HelloWebServiceClient { public static void main (String args) throws MalformedURLException { // создаем ссылку на wsdl описание URL url = new URL ("http://localhost:1986/wss/hello?wsdl" ) ; // Параметры следующего конструктора смотрим в самом первом теге WSDL описания - definitions // 1-ый аргумент смотрим в атрибуте targetNamespace // 2-ой аргумент смотрим в атрибуте name QName qname = new QName ("http://ws.сайт/" , "HelloWebServiceImplService" ) ; // Теперь мы можем дотянуться до тега service в wsdl описании, Service service = Service. create (url, qname) ; // а далее и до вложенного в него тега port, чтобы // получить ссылку на удаленный от нас объект веб-сервиса HelloWebService hello = service. getPort (HelloWebService. class ) ; // Ура! Теперь можно вызывать удаленный метод System. out. println (hello. getHelloString ("JavaRush" ) ) ; } } Максимум комментариев по коду я дал в листинге. Добавить мне нечего, поэтому запускаем (Shift+F10). Мы должны в консоли увидеть текст: Hello, JavaRush! Если не увидели, то видимо забыли запустить веб-сервис.Заключение
В данном топике был представлен краткий экскурс в веб-сервисы. Еще раз скажу, что многое из того, что я написал – это мои догадки по поводу того, как это работает, и поэтому мне не стоит сильно доверять. Буду признателен, если знающие люди меня поправят, ведь тогда я чему-нибудь научусь. UPD.Язык описания Web-сервисов (WSDL)
В последних нескольких примерах вы могли видеть отдельные фрагменты WSDL-кода. Напомним, что WSDL – это основанная на XML грамматика, предназначенная для описания возможностей взаимодействия внешних клиентов с Web-методами, доступными по данному адресу URL в рамках каждого из поддерживаемых протоколов связи. Во многих отношениях WSDL-документ может рассматриваться, как "контракт" между клиентом Web-сервиса и самим Web-сервисом. Это еще один метаязык. В частности, WSDL используется для описания следующих характеристик любого доступного Web-метода:
Имя Web-метода XML;
Число, тип и порядок следования параметров (если таковые имеются);
Тип возвращаемого значения (если таковое предусмотрено);
Условия вызова HTTP GET, HTTP POST и SOAP.
В большинстве случаев WSDL-документы генерируются автоматически соответствующим Web-сервером. Напомним, что при добавлении суффикса?wsdl к адресу URL, указывающему на файл *.asmx, Web-сервер генерирует WSDL-документ для указанного Web-сервиса XML.
http://locаlhost/SomeWS/theWS.asmx?wsdl
Но если IIS автоматически генерирует WSDL-документ для данного Web-сервиса XML, зачем тогда нужно глубокое понимание синтаксиса генерируемых WSDL-данных? Ответ обычно зависит от того, как ваш сервис будет использоваться внешними приложениями. В случае Web-сервисов XML, предназначенных для "внутреннего" использования, сгенерированного Web-сервером WSDL-кода будет, как правило, достаточно.
Между тем. вполне возможно начать разработку Web-сервиса XML с создания WSDL-документа вручную (об этом уже говорилось выше). Главная идея начала разработки с создания WSDL-документа связана с вопросами совместимости. Вспомните о том, что до появления спецификации WSI различные инструменты построения Web-сервисов нередко генерировали несовместимые WSDL-описания. Если начинать разработку с WSDL-кода, вы можете построить документ так, как требуется.
Как вы можете догадаться, для начала разработки Web-сервиса XML с создания WSDL-документа требуется очень хорошее знание грамматики WSDL, обсуждение которой в контексте этой главы не предусмотрено. Но мы рассмотрим базовую структуру WSDL-документа. Разобравшись в основах, вы сможете оценить пользу утилиты командной строки wsdl.exe.
Замечание. Самую свежую информацию о языке WSDL можно найти на страницах http://www.w3.org/tr/wsdl .
Определение WSDL-документа
Действительный документ WSDL открывается и закрывается корневым элементом ‹definitions›. В открывающем дескрипторе обычно определяются различные атрибуты xmlns. Они задают пространства имен XML, определяющие различные подчиненные элементы. Как минимум, элемент ‹definitions› должен указать пространство имен, где определены сами элементы WSDL (http://schemas.xmlsoap.org/wsdl). Для того чтобы быть полезным, открывающий дескриптор ‹definitions› должен, кроме того, указать пространства имен XML, определяющие простые типы данных WSDL, типы XML-схемы, элементы SOAP, а также целевое пространство имен. Например, вот как выглядит раздел ‹definitions› для нашего Web-сервиса калькулятора.
‹wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns-mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:tns="http://www.IntertechTraining.com/"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:http="http://schemes.xmlsoap.оrg/wsdl/http/"
targetNamespace="http://www.IntertechTraining.com/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"›
‹/wsdl :definitions›
В контексте корневого элемента вы можете найти пять подчиненных элементов. Общий вид WSDL-документа должен быть примерно таким.
‹?xml version="1.0" encoding="utf-8"?›
‹wsdl:definitions …›
‹wsdl:types›
‹!-- Список типов, доступных для данного Web-сервиса - -›
‹wsdl:/types›
‹wsdl:message›
‹!-- Формат сообщений - -›
‹wsdl:/message›
‹wsdl:portType›
‹!-- Информация портов - -›
‹wsdl:/portType›
‹wsdl:binding›
‹!-- Информация связывания - -›
‹wsdl:/binding›
‹wsdl:service›
‹!-– Информация о самом Web-сервисе XML - -›
‹wsdl:/service›
‹wsdl:/definitions›
Как и следует ожидать, каждый из этих подчиненных элементов будет содержать дополнительные элементы и атрибуты, уточняющие описание имеющихся возможностей. Давайте по очереди рассмотрим наиболее важные из допустимых узлов.
Элемент ‹types›
Сначала мы рассмотрим элемент ‹types›, который содержит описания всех типов данных, предлагаемых Web-сервисом. Вы, возможно, знаете, что язык XML сам определяет ряд "базовых" типов данных, и все они определены в рамках пространства имен XML http://www.w3.org/2001/XMLSchema (которое должно быть указано в контексте корневого элемента ‹definitions›). Возьмем, например, метод Subtract() нашего Web-сервиса калькулятора, имеющий два входных параметра целочисленного типа. В терминах WSDL тип System.Int32 среды CLR описывается в контексте элемента ‹complexType›.
‹s:еlement name= "Subtract"›
‹s:sequence›
‹s:element minOccurs="1 " maxOccurs="1 " name="x " type="s:int " /›
‹s:element minOccurs=""1 " maxOccurs="1 " name="y " type="s:int " /›
‹/ s:sequence›
‹/s:complexType›
‹/s:element›
Целое число, возвращаемое методом Subtract(), также описывается в рамках элемента ‹types›.
‹s:element name= "SubtractResponse "›
‹s:complexType›
‹s:sequence›
‹s:element minOccurs="1 " maxOccurs= "1 " name="SubtractResult " type="s:int "/›
‹/s:sequence›
‹ /s:complexType›
‹/s:element›
Если вы имеете Web-метод, возвращающий или получающий пользовательские типы данных, они также появятся в контексте элемента ‹complexType›. Детали того, как с помощью Web-метода сделать доступными пользовательские типы данных.NET, мы рассмотрим позже. Для примера предположим, что вы определили Web-мeтод, возвращающий структуру с именем Point.
public struct Point {
public string pointName;
WSDL-описание для этой "сложной структуры" будет выглядеть примерно так.
‹s:complexType name="Point "›
‹s:sequence›
‹s:element minOccurs="1 " maxOccurs="1 " name="x " type="s:int " /›
‹s:element minOccurs="1 "" maxOccurs="1 " name="y " type= "s:int " /›
‹s:element minOccurs="0 " maxOccurs="1 " name="рointName " type="s:string " /›
‹/s:sequence›
‹/s:complexType›
Элемент ‹message›
Элемент ‹message› используется для определения формата обмена запросами и ответами данного Web-метода. Поскольку один Web-сервис позволяет передачу множества сообщений между отправителем и получателем, одному WSDL-документу позволяется определять множество элементов ‹message›. Как правило, в этих определениях используются типы, указанные в рамках элемента ‹types›.
Независимо от количества элементов ‹message›, определенных в документе WSDL, они обычно "присутствуют" парами. Первое определение представляет входной формат сообщения, а второе – выходной формат того же сообщения. Например, метод Subtract() Web-сервиса CalculatorWebService определяет следующие элементы ‹message›.
‹wsdl:message name="SubtractSoapIn "›
‹wsdl:part name="parameters" element="tns:Subtract" /›
‹/wsdl:message›
‹wsdl: message name="SubtractSoapOut "›
‹wsdl:part name="parameters" element="tns:SubtractResponse" /›
‹/wsdl:message›
Здесь вы видите только связь SOAP соответствующего сервиса. Как говорилось в начале этой главы, Web-сервисы XML могут вызываться с помощью SOAP или HTTP-методов GET и POST. Но если вы разрешите связь HTTP POST (соответствующие объяснения будут предложены позже), генерируемый WSDL-код должен продемонстрировать следующие данные ‹message›.
‹wsdl: message name="SubtractHttpPostIn "›
‹part name="n1" type="s:string" /›
‹part name="n2" type="s:string" /›
‹wsdl:/message›
‹wsdl:message name="SubtractHttpPostOut "›
‹part name="Body" element="s0:int" /›
‹wsdl:/message›
Элементы ‹message› сами по себе не слишком полезны. Однако на эти определения сообщений ссылаются другие части WSDL-документа.
Замечание. Не все Web-методы требуют и запроса, и ответа. Если Web-метод является "односторонним", для него необходим только элемент ‹message› запроса. Обозначить Web-метод, как односторонний, можно с помощью атрибута .
Элемент ‹portType›
Элемент ‹portType› определяет различные связи, которые могут возникать между клиентом и сервером, и каждая такая связь представляется вложенным элементом ‹operation›. Несложно догадаться, что самыми типичными операциями здесь должны быть SOAP, HTTP GET и HTTP POST. Однако есть и другие операции. Например, односторонняя операция позволяет клиенту отправить сообщение данному Web-серверу, но не получить ответ (это похоже на вызов метода без ожидания возвращаемого значения). Операция "требование-ответ" позволяет серверу отправить, запрос во время ответа клиента (что можно рассматривать, как дополнение операции "запрос-ответ").
Чтобы проиллюстрировать формат необязательного вложенного элемента ‹operation›, рассмотрим WSDL-определение для метода Subtract().
‹wsdl portType name="CalculatorWebServiceSoap "›
‹wsdl:operation name="Subtract "›
‹wsdl:input message="tns:SubtractSoapIn " /›
‹wsdl:output message="tns:SubtractSoapOut " /›
‹ /wsdl:operation›
‹wsdl:/portType›
Обратите внимание на то, как элементы ‹input› и ‹output› ссылаются на соответствующее имя сообщения, определенное в рамках элемента ‹message›. Если бы для метода Subtract() был разрешен HTTP-метод POST, вы бы увидели следующий дополнительный элемент ‹operation›.
‹wsdl:portType name="CalculatorWebServiceHttpPost"›
‹wsdl:input message="s0:SubtractHttpPostIn
" /› ‹wsdl:output message= "s0:SubtractHttpPostOut
" /› ‹
wsdl:/operation› ‹wsdl:/portType› Наконец, учтите то, что если данный Web-метод описан с помощью свойства Description, элемент ‹operation› будет содержать вложенный элемент ‹documentation›. Элемент ‹binding› Этот элемент указывает точный формат обмена GET, POST и SOAP. Это самый "многословный" из всех элементов, содержащихся в контексте корневого элемента ‹definition›. Вот, например, определение элемента ‹binding› с описанием того, как вызывающая сторона может взаимодействовать с Web-методом MyMethod(). используя SOAP. ‹wsdl:binding name="СаlculatorWebServiceSoap12" type="tns:CalculatorWebServiceSoap
"› ‹soap12:binding transport="http://schemas.xmlsoap.org/soap/http
" /›
‹wsdl:operation name= "Subtract
"› ‹soap12:operation soapAction="http://www.IntertechTraining.com/Subtract
" style="document" /› ‹wsdl:input› ‹soap12:body use="literal
" /› ‹/wsdl:input› ‹wsdl:output› ‹soap12:body use="literal
" /› ‹/wsdl:output› ‹/wsdl:operation› ‹/wsdl:binding› Элемент ‹service› Наконец, у нас есть элемент ‹service›, который указывает характеристики самого Web-сервиса (например, его URL). Главной задачей этого элемента является описание множества портов, открытых данным Web-сервером. Для этого элемент ‹services› может использовать любое число вложенных элементов ‹port› (не путайте их с элементом ‹portType›). Вот как выглядит элемент ‹service› для CalculatorWebService. ‹wsdl:service name="CalculatorWebService
"› ‹wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"›
Чудесный Web-сервис калькулятора
‹/wsdl:documentation› ‹wsdl:port name="CalculatorWebServiceSoap"
binding="tns
:CalculatorWebServiceSoap"
› ‹soap:address location="http://localhost:1109/CalculatorWebService/ Service.asmx"
/› ‹/wsdl:port› ‹wsdl:port name="CalculatorWebServiceSoap12"
binding= "tns
:CalculatorWebServiceSoap12
"› ‹soap12:address location="http://localhost:1109/CalculatorWebService/Service.asmx"
/› ‹/wsdl:port› ‹/wsdl:service› Итак, как видите, WSDL-код, автоматически возвращаемый сервером ITS, не является сверхсложным, но, поскольку WSDL представляет собой грамматику на основе XML, этот код достаточно "многословен". Тем не менее, теперь вы должны лучше понимать роль WSDL, так что давайте рассмотрим немного подробнее протоколы связи Web-сервисов XML. Замечание.
Напомним, что пространство имен System.Web.Services.Description содержит множество типов, которые позволяют программно читать и обрабатывать "сырой" WSDL-код (можете проверить сами, если вас это интересует). Как WSDL 1.1 определяет Web-сервисы, и как создать модели на языке Java для верификации и преобразования WSDL-документов Web-сервисы ― важная функция технологии Java™ в корпоративных вычислениях. В этом цикле статей консультант по XML и Web-сервисам Денис Сосновский рассказывает об основных структурах и технологиях, ценных для Java-разработчиков, использующих Web-сервисы. Следите за статьями цикла, чтобы быть в курсе последних разработок в данной области и знать, как применить их в своих собственных проектах. Web-сервисы для корпоративных приложений в значительной степени зависят от использования определений сервисов. Определения сервисов описывают основное соглашение между поставщиком услуг и любым потенциальным потребителем, детализируя типы функций, предоставляемых сервисом, и сообщения в рамках каждой функции. Поставщики и потребители свободны в выборе способа реализации своих объектов обмена в той мере, в какой фактические сообщения, которые они посылают, соответствуют определению сервиса. Использование определения сервиса с описанием способа обмена XML-сообщениями ― это то, что отличает Web-сервисы от более ранних технологий распределенного программирования. Предлагались различные методы определения Web-сервисов, но наиболее широко используемым подходом остается WSDL 1.1. WSDL 1.1 имеет некоторые недостатки, в том числе чрезмерно сложную структуру, которая затрудняет его чтение для непосвященных. Он страдает также от отсутствия авторитетного формального определения, что привело к последовательным «уточнениям», которые заполняют некоторые пробелы в исходном документе спецификации. В результате стеки Web-сервисов стараются обрабатывать документы WSDL 1.1 как можно более гибко. Эта гибкость может усилить путаницу в понимании WSDL 1.1, так как разработчики видят широкий спектр WSDL-структур без каких-либо указаний на то, какой подход предпочтительнее. В этой статье мы покажем, как разобрать документы WSDL 1.1, и рассмотрим первые части модели Java для проверки WSDL-документов и их преобразования в стандартную форму. В этой статье используются: Редакция 1.1 WSDL, опубликованная в начале 2001 года, технически заменена рекомендациями W3C WSDL 2.0, опубликованными в 2007 году. WSDL 2.0 предлагает более четкую структуру, чем WSDL 1.1, наряду с большей гибкостью. Но WSDL 2.0 страдает от проблемы курицы и яйца: WSDL 2.0 не используется широко, потому что не поддерживается широко, а так как он широко не используется, у разработчиков стеков Web-сервисов мало стимулов его поддерживать. Несмотря на все его недостатки, для большинства целей WSDL 1.1 достаточно хорош. Оригинальная спецификация WSDL 1.1 была неточной в отношении количества используемых функций. Так как в центре внимания WSDL была работа с определениями служб SOAP, он включал также поддержку функций SOAP (таких как кодирование rpc), которые позднее оказались нежелательными. Организация Web Services Interoperability Organization (WS-I) решила эти проблемы в Базовом профиле (BP), который содержит практические рекомендации по Web-сервисам с использованием SOAP и WSDL. BP 1.0 был утвержден в 2004 году, а в 2006 году вышла редакция BP 1.1. В этой статье рассматривается WSDL 1.1 на базе рекомендаций BP WS-I и не затрагиваются фактически устаревшие функции, такие как кодирование rpc для SOAP. Предполагается, что структура XML-документов задается определениями XML-схемы. В первоначальную спецификацию WSDL 1.1 входит описание схемы, но эта схема в нескольких отношениях не соответствует текстовым описаниям. Позже это было исправлено в модифицированной версии схемы, но документ WSDL 1.1 не был отредактирован с учетом этого изменения. Затем группа BP WS-I решила внести еще больше изменений в схему WSDL и создала то, что преподносится как практические рекомендации к этой скользкой схеме. Документы, написанные для одной версии схемы, как правило, не совместимы с другими версиями (несмотря на то, что используется одно и то же пространство имен), но к счастью, большинство инструментов Web-сервисов в основном игнорирует схему и принимает все, что выглядит разумным. (См. ссылки на многие схемы WSDL в разделе ). Даже версия BP WS-I схемы WSDL 1.1 не очень помогает гарантировать соответствие спецификации документов WSDL 1.1. Схема не отражает всех ограничений BP WS-I, особенно в отношении порядка следования компонентов. Кроме того, XML-схема не способна обработать многие типы легко устанавливаемых ограничений в документах (такие как альтернативные атрибуты или необходимые дополнительные элементы из отдельной схемы). Поэтому проверка соответствия документа WSDL 1.1 спецификации WSDL 1.1 (с поправками, внесенными BP WS-I) включает в себя гораздо больше, чем просто выполнение валидации XML-схемы. Мы еще вернемся к данной теме в этой статье. Но сначала рассмотрим структуру описаний сервиса WSDL 1.1. В документах WSDL 1.1 используется фиксированный корневой элемент с удобным названием Существует также элемент Для полного описания сервиса, как правило, требуется, по крайней мере, один элемент каждого из этих типов, за исключением В листингах 1 и показан пример описания сервиса WSDL, разбитого на два WSDL-документа, так что компоненты описания интерфейса содержится в файле BookServerInterface.wsdl, а компоненты реализации ― в файле BookServerImpl.wsdl. В листинге 1 показан BookServerInterface.wsdl. В листинге 2 показан BookServerImpl.wsdl. Элемент Помимо определений элементов (и атрибутов) в пространстве имен WSDL 1.1, WSDL 1.1 определяет также дополнительные элементы. Они предназначены для заполнения конкретных ячеек в описаниях сервисов WSDL 1.1 для передачи дополнительной информации, необходимой для конкретного типа сервисов. Единственные дополнительные элементы WSDL 1.1, которые все еще широко используются, это привязки для SOAP 1.1 (они представлены в , в элементах Элемент Поскольку один элемент Помимо Сообщения, представленные элементами Элементы WSDL 1.1 определяет несколько шаблонов взаимодействия между клиентом и поставщиком услуг, представленных различными последовательностями дочерних элементов Каждый элемент Во многих отношениях SOAP 1.1 широко используется для Web-сервисов с момента опубликования спецификации в 2000 году. Версия SOAP 1.2 разработана при более широкой поддержке отрасли через W3C и опубликована в качестве официального стандарта W3C в 2007 году. SOAP 1.2 лучше документирована и чище, чем SOAP 1.1, причем некоторые уродливые аспекты 1.1 хирургически удалены. Несмотря на эту очищенную структуру, для большинства Web-сервисов практических различий между ними немного. Вероятно, наиболее существенная особенность SOAP 1.2 заключается в том, что это единственный официально поддерживаемый способ использования расширенной поддержки SOAP-вложений XML-binary Optimized Packaging (XOP) и SOAP Message Transmission Optimization Mechanism (MTOM). В цикле Web-сервисы Java
я до сих пор использовал SOAP 1.1, потому что некоторые старые стеки не поддерживают SOAP 1.2, но для разработки новых Web-сервисов 1.2, вероятно, является лучшим выбором. Элементы Дочерние элементы Расширения, определяемые WSDL, вступают в игру в Внутри каждого дочернего элемента Последним компонентом описания сервиса WSDL является элемент Не удивительно, что при всех вариациях схем и правил для документов WSDL 1.1 многие документы не соответствуют практическим рекомендациям BP WS-I. Поддержка всеми стеками Web-сервисов многих отклонений от практических рекомендаций помогла увековечить использование устаревших или неправильных конструкций, что привело к распространению дурной практики по всей отрасли. И я определенно не застрахован от этой инфекции – просматривая WSDL-документы, которые я приводил в качестве примеров кода для этого цикла, я к своему удивлению обнаружил, что ни один из них не является полностью корректным. Так что когда я решил написать эту статью, я подумал, что было бы хорошо включить в нее инструмент, с помощью которого можно проверять WSDL-документы на соответствие практическим рекомендациям. Казалось бы, отсюда всего один шаг до преобразования WSDL-документов в правильную форму, при условии, что оригинальный WSDL свободен от ошибок. Но работы оказалось значительно больше, чем я первоначально планировал, и полную информацию об этой модели я включу в следующие две статьи этого цикла. Для работы с WSDL-документами на языке Java построено множество различных моделей, в том числе широко используемый язык описания Web-сервисов для Java Toolkit (WSDL4J), который представляет собой эталонную реализацию JSR 110 (см. раздел ). Ни одна из этих моделей не соответствует тому, что я собирался сделать, ввиду двоякой постановки задачи: во-первых, чтение WSDL-документов в любой полуразумной форме и сообщение об ошибках и отклонениях от практических рекомендаций, и во-вторых, написание безошибочных WSDL-документов, переформатированных в форму, соответствующую практическим рекомендациям. WSDL4J, например, не сохраняет порядок вводимых элементов, так чтобы можно было сообщать о проблемах порядка их следования, и не обрабатывает определения схемы, так что его нельзя напрямую использовать для проверки ссылок из элементов В этой статье я использую термин верификация
для обозначения проверки правильности WSDL-документа, потому что альтернативный термин валидация
, обычно используемый для XML-документов, означает проверку документов на соответствие определению схемы. Ранее я уже частично реализовал модель WSDL для использования с привязкой данных JiBX в рамках проекта JiBX/WS. Эта модель предназначена только для вывода и включает относительно небольшое число классов, которые в некоторых случаях объединяют данные из вложенных элементов структуры WSDL XML ( Еще один вариант ― генерирование кода из схемы BP WS-I для WSDL 1.1. Увидев это, я понял, что простое использование созданных классов напрямую приведет к путанице, так как схема включает избыточные типы, а также некоторые неудобные конструкции, которые используются для представления различных моделей обмена сообщениями (некоторые из которых затем были запрещены текстом BP WS-I). Так что в конечном итоге я составил классы вручную, хотя результат оказался почти таким же, как если бы я начал с кода, сгенерированного из схемы, и просто сократил ненужное дублирование и сложность. Привязка данных JiBX поддерживает несколько связей с одними и теми же классами, так что мне удалось создать привязку ввода для обработки всего спектра вариантов, допускаемых любой версией WSDL 1.1, хотя настройка привязки выхода для вывода WSDL была только в форме, соответствующей практическим рекомендациям. В листинге 3 показана часть класса Definitions , соответствующая корневому элементу Организация данных дочерних элементов в показывает, каким образом модель поддерживает как общую форму ввода, так и форму вывода в соответствии с практическими рекомендациями. Вместо единого списка дочерних элементов всех типов, используются отдельные списки для каждого типа. Привязка ввода JiBX обрабатывает дочерние элементы как неупорядоченный набор, вызывая специфический для данного типа элементов set-метод всякий раз, когда дочерний элемент находится не на своем месте. Вместо того чтобы заменять какое-либо из предшествующий значений, set-метод добавляет экземпляр в типизированный список, как видно из set-метода addMessage() , который используется для дочерних элементов В любом из элементов WSDL разрешены дополнительные атрибуты и элементы (как правило, все атрибуты или элементы, которые не используют пространство имен WSDL 1.1). Примером таких дополнительных элементов служат конфигурации WS-Policy, встроенные в WSDL-документы из предыдущих статей данного цикла, как и ссылки на фактические политики. Лучше всего, чтобы эти дополнительные элементы предшествовали любым дочерним элементам из пространства имен WSDL 1.1, и именно так они обрабатываются в привязке вывода. Привязка ввода обрабатывает дополнительные элементы и атрибуты с помощью кода базового класса из классов элементов WSDL, не показанного в , и позволяет элементам следовать в любом порядке (генерируя предупреждение, если они следуют за элементом из пространства имен WSDL 1.1). Модель обрабатывает известные элементы, используя отдельные привязки для каждого дополнительного пространства имен, каждая из которых имеет свой собственный набор классов. Я рассмотрю обработку этих дополнительных элементов более подробно в следующем выпуске Web-вервисов Java
, где будет подробнее представлен и исходный код. Некоторая базовая верификация данных WSDL выполняется по мере добавления немаршаллизованных объектов, соответствующих элементам, в древовидную структуру WSDL-документа, как показано в коде addMessage() в конце . Этот код использует метод checkAdd() для проверки порядка следования дочерних элементов и метод addName() для проверки того, что представлено допустимое имя (текст соответствует типу схемы NCName и значение уникально в пределах типа элемента), и отображения имени на объект. Но это только проверка самой основной информации для отдельного элемента; для проверки других свойств каждого элемента и взаимосвязей между элементами необходим дополнительный код верификации. JiBX позволяет вызывать обработчики пользовательских расширений в рамках процесса маршаллинга и демаршаллинга. Для исполнения логики верификации модель WSDL использует один из таких дополнительных обработчиков, метод post-set. Метод post-set вызывается после завершения демаршаллинга связанного объекта, так что это часто хороший способ выполнения проверок типа верификации объектов. В случае проверки WSDL простейший подход – это выполнение всей верификации объектов из одного метода post-set для корневого элемента В этой статье изложены основы структуры и использования WSDL и введение в модель данных Java для WSDL, предназначенную для поддержки верификации WSDL-документов и их преобразования в форму, соответствующую практическим рекомендациям. Следующая статья продолжит эту тему, рассматривая проблемы, часто встречающиеся при написании утверждений WS-Policy и WS-SecurityPolicy. Кроме того, в ней будет более подробно рассмотрена модель WSDL и процесс верификации, в том числе расширение модели с включением утверждений WS-Policy/WS-SecurityPolicy, встроенных в WSDL.Серия контента:
Об этом цикле статей
Разбор WSDL 1.1
Используемые пространства имен
Компоненты описания
Листинг 1. BookServerInterface.wsdl
Листинг 2. BookServerImpl.wsdl
Детали компонентов
Рисунок 1. Связи между компонентами WSDL
Сравнение SOAP 1.1 и 1.2
Работа с WSDL
Модель WSDL
Валидация и верификация
Листинг 3. Класс Definitions (частично)
public class Definitions extends ElementBase
{
/** Перечисление дочерних элементов в ожидаемом порядке. */
static enum AddState {
invalid, imports, types, message, portType, binding, service };
/** Список разрешенных имен атрибутов. */
public static final StringArray s_allowedAttributes =
new StringArray(new String { "name", "targetNamespace" });
/** Валидация используемого контекста. */
private ValidationContextВерификация модели
Другие дополнения