Разработка веб-служб средствами Java. Ильдар ХабибуллинРазработкаWebслужбсредствами
![]()
|
Кроме атрибутов в нем может быть атрибут actor, указывающий адресом URI конкретный SOAP-сервер, которому предназначено послание. Дело в том, что SOAP-послание может пройти через несколько SOAP- серверов или через несколько приложений на одном сервере. Эти приложе- ния выполняют предварительную обработку блоков заголовка послания и передают его друг другу. Все эти серверы и/или приложения называются SOAP-узлами (SOAP nodes). Спецификация SOAP не определяет правила прохождения послания по цепочке серверов. Для этого разрабатываются другие протоколы, например, Microsoft WS-Routing. Атрибут actor задает целевой SOAP-узел — тот, который расположен в конце цепочки и будет обрабатывать заголовок полностью. Значение атрибута actor показывает, что обрабатывать заголовок будет первый же сервер, получивший Атрибут actor может встречаться в отдельных блоках заголовка, указывая узел- обработчик этого блока. После обработки блок удаляется из SOAP- послания. В версии 1.2 атрибут actor заменен атрибутом role, потому что в этой вер- сии SOAP каждый узел играет одну или несколько ролей. Спецификация пока определяет три роли SOAP-узла. • Роль играет конечный, целевой узел, который будет обрабатывать заголовок. • Роль http://www.w3.org/2002/06/soap-envelope/role/next играет промежу- точный или целевой узел. Такой узел может играть и другие, дополни- тельные роли. • Роль http://www.w3.org/2002/06/soap-envelope/role/none не должен играть ни один SOAP-узел. Распределенные приложения, исходя из своих нужд, могут добавить к этим ролям другие роли, например, ввести промежуточный сервер, проверяющий цифровую подпись и определить для него эту роль какой-нибудь строкой Значением атрибута role может быть любая строка URI, показывающая роль узла, которому предназначен данный блок заголовка. Значением по умолчанию для этого атрибута служит пустое значение, то есть, просто пара кавычек, или строка URI Глава 3. Протокол SOAP и Web Services 137 Значение атрибута role показывает, что блок должен быть обработан узлом, играющим роль, определенную такой же строкой. Еще один атрибут элемента или совсем не обрабатывать послание. Это повышает точность обработки послания. В версии SOAP 1.2 вместо цифры о надо писать слово false, а вместо циф- ры 1 писать true. В тело заголовка блоками (blocks) заголовка. Их имена обязательно помечаются префиксами. В блоках заголовка могут встретиться атрибуты role или actor и mustunderstand. Их действие будет относиться только к данному блоку. Это позволяет обрабатывать отдельные блоки заголовка промежуточными SOAP- узлами, теми, чья роль совпадает с ролью, указанной атрибутом role. В листинге 3.1 приведен пример такого блока. Листинг Заголовок с одним блоком - com/transaction" 5 Элементы, вложенные в блоки заголовка, уже не называются блоками. Они не могут содержать атрибуты role, actor И mustunderstand. Элемент обязательно записывается сразу за элементом если он есть в послании, или первым в SOAP-послании, если заголовок от- сутствует. В элемент можно вложить произвольные элементы, спе- цификация никак не определяет их структуру. Впрочем, определен один элемент содержащий сообщение об ошибке. 138 Разработка Web-служб средствами Java Сообщение об ошибке Если обрабатывая поступившее к нему SOAP-послание, заметит ошибку, то он прекратит обработку и отправит клиенту SOAP- послание, в тело которого запишет один элемент с сообщением об ошибке. В сообщении, записанном в теле элемента версии SOAP 1.1 выде- ляются четыре части, описанные следующими вложенными элементами. • Код ошибки — сообщение, показывающее тип ошибки. Оно предназначено для программы, обрабатывающей ошибки. • Описание ошибки предназначенное для человека. • Место обнаружения ошибки — адрес URI сервера, заме- тившего ошибку. Полезно, когда послание проходит цепочку SOAP- узлов, для уточнения природы ошибки. Промежуточные SOAP-узлы обя- зательно записывают этот элемент, целевой SOAP-сервер не обязан это делать. • Детали ошибки — описывают ошибки, встреченные в теле послания, но не в его заголовке. Если при обработке тела ошиб- ки не обнаружены, то этот элемент отсутствует. Например: Must Understand Error Глава 3. Протокол SOAP и Web Services 139 Версия SOAP 1.2 изменила содержание элемента Как описано в пространстве имен http://www.w3.org/2002/06/soap-envelope, в него входят два обязательных элемента и три необязательных элемента. Обязательные элементы. • Код ошибки . Он содержит обязательный вложенный элемент с кодом ошибки и необязательный вложенный элемент 140 Разработка Web-служб средствами Java Типы ошибок Список кодов ошибок постоянно меняется и расширяется. Версия 1.1 опре- деляет четыре типа ошибок. • — пространство имен неопознано. Может быть, оно устарело или его имя написано неправильно. — блок заголовка, помеченный атрибутом со значением 1, не отвечает своему синтаксису, определенному в схеме до- кумента. • client — документ XML, содержащий послание, неправильно сформи- рован и по этой причине сервер не может его обработать. Клиенту сле- дует изменить послание. Глава 3. Протокол SOAP и Web Services • — сервер не может обработать правильно записанное послание по своим внутренним причинам. Версия 1.2 определяет пять типов ошибок. — пространство имен неопознано. Может быть, оно устарело или его название написано неправильно, или в послании встре- тилось имя элемента не определенное в этом пространстве имен. В заголовок ответа сервер записывает элемент • — блок заголовка, помеченный атрибутом со значением true, не отвечает своему синтаксису, определенному в схеме документа. Сервер записывает в заголовок ответа элементы • DataEncodingUnknown — в послании встретились непонятные данные, может быть, они записаны в неизвестной кодировке. • — документ XML, содержащий послание, неправильно сформи- рован и по этой причине сервер не может его обработать. Клиенту сле- дует изменить послание. • Receiver — сервер не может обработать правильно записанное послание по своим внутренним причинам, например, отсутствует нужный XML- парсер. Сервер может добавить к этим типам ошибок какие-то свои типы. Обычно они детализируют стандартные типы, и сообщения о них появляются в эле- ментах Листинг 3.3. Ответ сервера с сообщением об ошибке типа VersionMlsmatch 142 Разработка Web-служб средствами Java • Листинг З.4. Ответ сервера с сообщением об ошибке MustUnderstand ?> > /> Глава 3. Протокол SOAP и Web Services One or more mandatory headers not understood Типы данных SOAP В SOAP-посланиях передаются данные самых разных типов: числа, даты, строки символов, массивы, структуры. Определение типов этих данных вы- полняется, как обычно, в схемах XML. Схема может быть записана любым способом, но чаще всего применяется язык XSD, который мы разобрали в главе 1. Типы, определенные в схеме, заносятся в пространство имен, идентификатор которого служит значением атрибута Атри- бут encodingstyle может появиться в любом элементе SOAP-послания, но версия SOAP 1.2 запрещает его появление в корневом элементе Указанное атрибутом пространство имен будет известно в том элементе, в котором записан атрибут, и во всех вложенных в него элементах. Конечно, какие-то из вложенных элементов могут изме- нить пространство имен своим атрибутом encodingstyle. Стандартное пространство имен, в котором расположены имена типов дан- ных SOAP 1.1, называется У те- кущей черновой версии SOAP 1.2 идентификатор пространства имен — Идентификатор того или иного пространства имен, в котором определены типы данных, обычно получает Разработка Web-служб средствами Java префикс или SOAP-ENC. Вот обычное описание наиболее часто приме- няемых пространств имен: В основном типы данных, определенные в пространстве епс, совпа- дают с типами данных языка XSD, описанными в главе 1. Это не случайно. Создатели протокола SOAP намеревались просто взять имена типов языка XSD, долго ждали окончания работы над этим языком, не дождались — и определили свое пространство имен, включив в него черновую версию язы- ка XSD. В частности, полностью совпадают простые типы: числа, даты, строки, логические значения. Интересно, что в пространстве имен епс описаны специальные элементы XML, типы которых — простые типы XSD. Имена этих элементов совпада- ют с именами соответствующих простых типов XSD. Например, тип эле- мента Элемент можно использовать так: У этого элемента фактически нет имени, он только показывает, что в его теле следует записывать целое число. Такие элементы удобно использовать в массивах. Для того чтобы на такой элемент можно было сослаться, опре- делен атрибут id: Атрибут id, определенный вместе с элементом Знак номера # означает ссылку на имя, определенное в другом элементе. Атрибут ref можно использовать, как в языке HTML, для ссылок на другие документы. Например: Глава 3. Протокол SOAP и Web Services /> В версии SOAP 1.1 атрибут ref назывался href. Разумеется, для указания типа элемента можно использовать обычную для документов XML конструкцию (см. главу например, опреде- лить элемент Массивы В пространстве имен определен тип массива Array. Этот тип не определяет ни количество элементов масси- ва, ни их тип. Все это надо уточнить позднее. В схеме, описывающей SOAP-послание, можно описать элемент типа массив, например, так: После этого в SOAP-послании можно определить конкретный массив: Можно сделать все определение целиком прямо в SOAP-послании: 146 Разработка Web-служб средствами Java Как видно из этих примеров, при определении массива атрибутом надо задать тип массива и количество его элементов. В одном массиве можно записать элементы разных типов. Типы элементов массива должны быть подтипами типа массива или совпадать с ним. Тип массива может быть любым, в том числе снова массивом, что отмечается квадрат- ными скобками, например, тип "массив из пяти целых чисел" записывается как i n t [ 5 ] , тип "неограниченный двумерный массив целых чисел" — int [, ] и так далее. Вот определение массива из десяти элементов, каждый элемент которого — двумерный массив целых чисел, число строк и столб- цов которого не определено: А вот массив, число элементов которого неизвестно, но каждый элемент — массив из двух строк:
Имена элементов массива (в примере, приведенном выше, повторяется имя item), не имеют никакого значения. Поэтому удобно применять элементы XML, соответствующие простым типам XSD, тем более, что элементы одно- го и того же массива могут быть разных типов. Например: При разборе массива его элементы отыскиваются по индексу. Начальный индекс равен нулю. Впрочем, в версии SOAP 1.1 допускаются массивы, ин- дексы которых начинаются с положительного числа. Такие массивы опреде- ляются с атрибутом следующим образом: Глава 3, Протокол SOAP и Web Services 147 с индексом 3 с индексом В версии SOAP 1.1 допускаются даже массивы, не все которых определены ("массивы с дырками"). Скажем, мы можем определить массив из 10 элементов, но задать в нем элементы с индексами 2 и 4. Это выполняется атрибутом position, например, определяем двумерный массив из 100 элементов, но записываем только два элемента: Версия SOAP 1.2 запрещает эти вольности, поскольку они сильно затруд- няют разбор массива сервером. В этой версии индексы массива всегда на- чинаются с нуля и все элементы массива должны быть записаны явно. Структуры Структуры определяются гораздо проще массивов. Поля структуры записы- ваются как элементы XML, вложенные в структуру. Они различаются по именам своих элементов XML. Все имена, разумеется, должны быть раз- личны. Например: Типы полей структуры могут быть какими угодно, в частности, снова струк- турами или массивами. Например, следующий элемент будет струк- турой, поле которой — массив: <Воок> Разработка Web-служб средствами Java <пате>Илья но следующий элемент <аВоок>: <аВоок> не будет структурой, поскольку у вложенных в него элементов совпадают имена. Это просто элемент XML какого-то сложного типа. Введение новых типов Итак, в пространстве имен епс уже определено множество простых типов, совпадающих с простыми типами языка XSD, и два сложных типа — масси- вы и структуры. Этих типов обычно хватает для работы с большинством Web-служб. При необходимости ввести новые типы, следует определить их в какой-либо схеме, например, на языке XSD. Их имена надо записать в новое пространство имен, а идентификатор этого пространства имен сде- лать значением атрибута В запросах клиента и ответах сервера новые типы обычно выражаются клас- сами Java. Преобразование классов Java в типы, определенные схемой XML, называется в протоколе SOAP (serialization), обратное преоб- разование называется (deserialization). После определения новых типов и классов Java, надо разработать методы сериализации и десе- риализации этих типов и классы, содержащие их. Затем клиенту и серверу SOAP надо указать соответствие классов Java определенным типам XML. Это выполняется разными способами, чаще всего пишутся конфигурацион- ные файлы или описание на языке WSDL. В результате получится специальный программный код, который надо пе- реносить на все Web-службы, использующие новые типы, а также встраи- Глава 3. Протокол SOAP и Web Services вать во все клиентские приложения. Это противоречит основному принципу Web Services — повсеместной доступности Web-услуг. Поэтому не стоит ув- лекаться введением новых типов данных в свои Web-службы. Процедурный стиль SOAP Послание, предназначенное для вызова удаленной процедуры или обраще- ния к методу удаленного объекта, оформляется очень просто. В тело послания помещается одна структура, имя которой совпадает с именем вызываемой процедуры или метода. В полях структуры перечис- ляются аргументы процедуры или метода. Имена полей совпадают с имена- ми аргументов, порядок следования полей в структуре совпадает с порядком следования аргументов в заголовке процедуры или метода. Версия SOAP 1.2 позволяет вместо структуры записать массив, имя которо- го совпадает с именем вызываемой процедуры или метода, а элементы со- держат значения аргументов процедуры или метода, причем элементы мас- сива должны строго соблюдать порядок следования аргументов в процедуре или методе. Пусть, например, SOAP-послание хочет обратиться к методу public String name, int number); следующим образом: String address = 2345678); Послание будет выглядеть так: Листинг 3.5. процедуры xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 150 Разработка Web-служб средствами Java В версии SOAP 1.1 ответ сервера записывается в теле одной структу- рой. Имя структуры не имеет значения, но по общему соглашению обычно повторяется имя процедуры с добавлением слова "Response". Для каждого выходного аргумента процедуры записывается поле структуры, содержащее значение этого аргумента. Имя поля совпадает с именем аргумента. Воз- вращаемое значение процедуры или метода заносится в первое поле этой структуры. Имя этого первого поля не имеет значения. Листинг 3.6 показывает ответ сервера, содержащий результат обращения к методу getAddress () В SOAP 1.1. Листинг 3.6. Ответ сервера с результатом работы процедуры. Версия SOAP 1.1 В версии SOAP 1.2 возвращаемое значение процедуры или метода записы- вается по-другому. Сначала определяется имя элемента, в тело которого бу- дет помещено возвращаемое значение. Имя элемента определяется в теле элемента Глава 3. Протокол SOAP и Web Services 151 org/2002/06/soap-rpc. Этому идентификатору обычно дается префикс Например: 25-4 Смысл такого двухступенчатого определения в том, чтобы дать возможность проверки типа возвращаемого значения. Результат работы процедуры или метода в версии SOAP 1.2 можно записать не только структурой, но и массивом. При этом возвращаемое значение должно быть первым элементом массива, следующие элементы должны со- держать значения выходных аргументов процедуры в порядке их располо- жения в заголовке процедуры. Листинг 3.7 показывает ответ сервера с результатом работы процедуры getAddress О В версии SOAP 1.2. • Листинг 3.7. Ответ сервера с результатом работы процедуры. Версия SOAP xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Садовая, 25-4 Сложные аргументы и результаты Аргументы процедуры или метода и их возвращаемые значения, имею- щие сложные типы, следует записывать при пересылке массивами или Разработка Web-служб средствами Java структурами. Пусть, например, в Web-службе есть класс, описывающий человека: public class Person) String name; // Имя. int age; // Возраст. public public name, int age){ = name; = age; public String return name; } public void name){ = name; } public int getAge(){ return age; } public void age){ = age; } } Этот класс используется в описании сотрудника: public class Person pers; // Имя и возраст int numb; // Табельный номер сотрудника. public public Person getPerson(){ return pers; } public void pers){ = pers; } public int getNumb(){ return numb; } public void setNumb(int numb)) = numb; } Допустим, что в этой Web-службе, в классе есть метод, возвращаю- щий список табельных номеров сотрудников, составленный по их имени и возрасту: public int[] person); Глава 3. Протокол SOAP и Web Services Обращение клиента к методу getClockNumbers о будет выглядеть так: Person ivanov = new "27"); inf = new int[] numbs = Сложный аргумент ivanov можно передать структурой, как показано в лис- тинге 3.9. Листинг 3.9. Передача объекта структурой ?> Можно передать аргумент ivanov и массивом, как показано в листинге 3.10. . . . . . . . ) Листинг Передача объекта массивом ?> 154 Разработка Web-служб средствами Java xmlns:xsd="http://www.w3.org/2001/XMLSchema"> Ответ сервера с результатом выполнения метода (), оформленным в виде массива, показан в листинге 3.11. Листинг Результат ?> Глава 3. Протокол SOAP и Web Services 155 "http://www.w3.org/2002/06/soap-encoding"> Пересылка послания протоколу HTTP Итак, SOAP-послание написано и готово к пересылке. Поскольку это про- стой текст, его можно пересылать по любому протоколу прикладного уров- ня: HTTP, SMTP, FTP, лишь бы он не исказил послание. Поэтому специ- фикация SOAP не указывает какой-то определенный протокол и не ограни- чивает их список. В следующих двух разделах этой главе мы приведем в качестве примера модель оформления SOAP-послания в виде почтового со- общения с одной и с несколькими частями. Тем не менее, SOAP-послания применяются в Web-технологии и поэтому наиболее часто передаются по наиболее распространенному в WWW прото- колу HTTP. При этом для посылки запроса применяется метод POST или GET. Спецификация протокола SOAP все-таки задает некоторые правила оформления POST-запроса. В версии SOAP 1.2 в POST-запросе в поле Content-Type заголовка записы- вается содержимого application и специально созданный и за- регистрированный МШЕ-подтип Короче говоря, в версии SOAP 1.2 HTTP-запрос выглядит так: POST /services/InfoServlet HTTP/1.1 156 Разработка Web-служб средствами Java Content-Type: charset="utf-8" Content-Length: nnnn version='1.0' ?> —> Конечно, в HTTP-заголовке могут быть и другие поля, определенные про- токолом В версии SOAP 1.1 сохранялся старый тип содержимого и присут- ствовало нестандартное для HTTP поле soAPAction заголовка, в котором строкой URI указывался адресат SOAP-послания, например: POST /services/InfoServlet HTTP/1.1 Content-Type: Content-Length: nnnn SOAPAction: ?> — > Строка URI, записанная в поле заголовка, предназначалась промежуточным серверам или прокси-серверам, не просматривающим тело HTTP-запроса. Пустое значение заголовка, то есть пара кавычек, означало, что адресатом будет строка URI, указанная в заголовке HTTP-запроса после слова POST. Отсутствие поля означало, что адресат не указан. Версия SOAP 1.2 отказалась от поля но, на всякий случай, до- бавила необязательный атрибут action к полю HTTP-заголовка content- Type, имеющий тот же смысл, что и поле SOAPAction. Например: Content-Type: application/soap+xml; \ charset="utf-8"; Глава 3. Протокол SOAP и Web Services 157 Использование метода GET Версия протокола SOAP 1.2 позволяет сделать запрос к SOAP-серверу по HTTP-методу GET. GET-запрос состоит только из заголовка, у него нет те- ла, следовательно, он не может передать Единственное, что он может сделать — это запросить у SOAP-сервера какое-то SOAP- послание, которое можно определить параметрами, переданными в GET- запросе. Например, можно передать аргументы name и метода приведенного выше в качестве примера, в заголовке GET-запроса: GET HTTP/1.1 Host: some.com Accept: text/html, В GET-запросе, в поле заголовка Accept, важно указать тип application/ ожидаемого SOAP-послания. Более того, спецификация SOAP 1.2 рекомендует простые аргументы SOAP- запроса дублировать в заголовке HTTP-запроса даже при пересылке SOAP- запроса методом POST. Листинг 3.12 показывает обращение к процедуре getciockNumbers о с уче- том этой рекомендации. Листинг Полный SOAP-запрос по POST POST HTTP/1.1 Host: some.com Content-Type: application/soap+xml; charset="utf-8" 553 ?> 158 Разработка Web-служб средствами Java 6/soap-encoding"> В любом случае, ответ сервера обычен: 200 ОК Content-Type: Content-Length: nnnn version='1.0' ?> > сервера —> В случае ошибки при обработке SOAP-послания Web-сервер должен дать КОД ответа 200 400 Bad Request ИДИ 500 I n t e r n a l Server Error. Код 400 записывается при возникновении SOAP-ошибки "sender", а код 500 — ошибок "Receiver". Пересылка послания по протоколу SMTP Правила пересылки SOAP-послания версии 1.2 по почтовому протоколу, описываются спецификацией "SOAP 1.2 Email" ("SOAP Version 1.2 Email Глава 3. Протокол SOAP и Web Services 159 Binding") (http://www.w3.org/TR/soapl2-email/). Впрочем, эти правила не добавляют ничего нового ни к правилам оформления SOAP-послания, ни к правилам оформления почтового сообщения, а только фиксируют их. Про- сто SOAP-послание служит телом обычного почтового сообщения. Вот пример почтового сообщения, содержащего SOAP-послание: From: ivan@some.com petr@another.com Subject: Some Message Date: 18 Nov 2002 13:20:00 GMT Message-Id: ?> ... Здесь SOAP-послание самого обычного вида... SOAP-послание с дополнениями Компоненты распределенного приложения часто должны обмениваться не только текстовыми SOAP-посланиями, но и графическими документами: изображениями, схемами, чертежами, рукописями. Такие документы обыч- но оформляются в бинарных форматах GIF, JPEG, PDF. Метод POST про- токола HTTP может передавать не только текстовую, но и самую разнооб- разную информацию, определяемую text, image, audio, video, application, multipart, message. Остается только совместить пере- дачу SOAP-посланий и бинарной информации. Для этого удобен multipart, введенный рекомендацией RFC 2046. multipart/related Тип multipart объединяет несколько сообщений разных типов, каким-то образом связанных между собой, в одно целое сообщение. Например, мож- но переслать фильм и звук к нему в одном HTTP-сообщении. Сообщение типа multipart начинается с заголовка, в котором, в частности, определяет- ся разделитель отдельных частей сообщения. После заголовка и пустой строки на отдельной строке записывается разделитель, после него первая часть сообщения, состоящая из своего заголовка, пустой строки и тела пер- вой части. Потом на отдельной строке записывается разделитель, после него Разработка Web-служб средствами Java вторая часть сообщения, опять состоящая из заголовка, пустой строки и тела и так далее. В конце всего сообщения опять ставится разделитель. строка создается двумя ASCII-символами CRLF, на языках C/C++, Java они записываются как Разделитель определяется обязательным параметром boundary поля Content-Type HTTP-заголовка и представляет собой любой набор символов, не совпадающий с начальными символами ни одной строки сообщения. Например: Content-Type: multipart/related; boundary=vT45fke0nS34x В строке, отделяющей одну часть от другой, перед разделителем записыва- ется два дефиса: В конце разделителя, завершающего все сообщение, ставятся еще два дефиса: Заголовки отдельных частей необязательны, каждая часть может начинаться с пустой строки. В заголовках важно только поле отсутствие которого означает Content-Type: text/plain; В зависимости от степени связанности сообщений в типе multipart разли- чают ПОДТИПОВ: alternative, parallel, related. Для Web Services наиболее удобен подтип related. Тип multipart/related описан в рекомендации RFC 2387. Это тип сооб- щения, состоящего из тесно связанных частей. В сообщении выделяется одна начальная (start) часть, с нее начинается обработка полученного сооб- щения. На начальную часть указывает необязательный параметр s t a r t поля content-Type заголовка Если параметр s t a r t отсутству- ет, то начальной считается первая часть сообщения. Тип содержимого на- чальной части записывается в обязательном параметре type поля content- Type. Например: Content-Type: multipart/related; start-info="-o -df type" Напомним, что параметры поля заголовка не должны разделяться символа- ми перевода строки, здесь это сделано только для наглядности. В технологии Web Services в начальной части записывается SOAP-послание, остальные части содержат дополнительную информацию. Глава 3. Протокол SOAP и Web Services Заголовок каждой части сообщения типа multipart/related снабжается полем content-ID, содержащим идентификатор этой части, уникальный в пределах всего Интернета. Он описан рекомендациями RFC 1521, RFC 1873 и RFC 2045 как уникальный адрес электронной почты, заключенный в уг- ловые скобки. Например: Content-ID: Идентификатор начальной части сообщения используется в параметре s t a r t для ссылки на нее. В начальной части записываются ссылки на иден- тификаторы других частей сообщения. Еще один необязательный параметр start-info поля содер- жит дополнительные сведения о начальной части сообщения, предназна- ченные программе, которая будет обрабатывать начальную часть. Например, это могут быть аргументы командной строки программы-обработчика. В заголовке каждой части сообщения может быть поле Disposition, описанное рекомендацией RFC 1806. Оно указывает, встроен- ная это часть, inline, или присоединенная, attachment. Любая часть сооб- щения может не находиться непосредственно в сообщении, а быть записан- ной в файл. В таком случае параметр поля filename содержит имя файла, содержащего данную часть сообщения. Например: Content-Disposition: attachment; Вот и все описание multipart/related. Приведем пример со- общения этого типа, состоящего из двух частей: HTML-текста и изображе- ния в формате GIF. 1.0 Content-Type: multipart/related; type=text/html Content-Type: text/html; Какой-то текст, затем показана картинка, Разработка Web-служб средствами Java ... дальнейший код ... В этом примере, в HTML-теге RFC 2111. После символов cid: просто записывается значение поля без угловых скобок. Рекомендация RFC 2557 добавила необязательное поле которое можно поместить в заголовок каждой части сообщения. Его значе- ние — строка URL, идентифицирующая данную часть сообщения так же, как И ПОЧТОВЫЙ адрес В Поле заголовка Content-ID. Поле Content-Location можно использовать вместе или вместо поля Его отличие от поля заключается в том, что его значение — URL, а не адрес электронной почты. Следовательно, при ссылке на него не надо применять схему cid. Вот ТОТ же С ПОЛЯ Content-Location И ссылки на него. 1.0 Content-Type: multipart/related; Content-Type: text/html; charset="windows-1251" Какой-то текст, затем показана картинка, Глава 3. Протокол SOAP и Web Services ... дальнейший код ... Оформление SOAP-послания с дополнениями В 2000 году консорциумом W3C выпущена спецификация "SOAP-послания с дополнениями" опирающаяся на версию SOAP 1.1. В спецификации описаны правила включения SOAP- послания в типа multipart/related и правила пересыл- ки его по протоколу HTTP. Правила эти просты. 1. SOAP-послание помещается в начальную часть MIME-сообщения типа 2. Тип MIME-сообщения устанавливается как text/xmi. 3. Заголовок начальной части содержит поле content-ID, a HTTP- заголовок, также как и заголовок MIME-сообщения, содержит поле с параметром s t a r t , ссылающимся на значение поля content-ID начальной части. Остальные части могут содержать поле Content-ID и/или Поле Content-Location. 4. Ссылки на другие части MIME-сообщения выполняются в SOAP- послании с помощью атрибута href. В листинге 3.13 приведен пример SOAP-послания, ссылающегося на два изображения в форматах GIF и JPEG. Листинг POST-запрос с SOAP-посланием и двумя изображениями POST HTTP/1.1 Host: Content-Type: multipart/related; type=text/xml; start=" Content-Length: XXXX SOAPAction: http://some.com/services/InfoServlet Content-Type: text/xmi; charset=utf-8 Content-Transfer-Encoding: 8bit Content-ID: Разработка Web-служб средствами Java ?> > Content-Type: Content-Transfer-Encoding: base64 Content-ID: ...Здесь GIF-изображение в коде Content-Type: Content-Transfer-Encoding: binary Content-ID: изображение в формате JPEG... Остается заметить, что подготовленное по этим прави- лам и содержащее SOAP-послание, самым естественным образом передается по почтовому протоколу SMTP. Формат сообщения DIME В мае 2001 года появились первые сообщения о том, что фирмы IBM и Microsoft предложили новый формат DIME (Direct Internet Message Encapsulation) для записи сообщений с дополнениями, не использующий multipart. В июне 2002 года появился черновой вариант спецификации DIME. Его можно посмотреть по адресу http://www.ibm.com/developerworks/ws-dime/. Сообщение DIME состоит из нескольких частей, называемых записями (record). В начале каждой записи идут несколько полей, отмечающих харак- Глава 3. Протокол SOAP и Web Services теристики записи. Каждая запись определяется тремя основными характе- ристиками: • длиной в байтах своего содержимого (поле DATA_LENGTH); • типом, записываемым строкой URI, или как-то по- другому (поле TYPE); • необязательным идентификатором — строкой URI (поле ID). Длина записи ограничена 2 32 - 1 байтами. Допустимы записи нулевой длины. Тип записи может быть любым. Длина поля TYPE заносится в поле а формат поля TYPE, — строка другое — определяется полем TYPET. ЕСЛИ ТИП записи определяется стро- кой URI, то значение поля равно если тип записи определяет- ся MIME-типом — то 0x02. Значение Охоз записывается, если тип записи неизвестен, при этом значение поля TYPE_LENGTH равно нулю. Поле T Y P E T равно 0x04, если содержимое записи отсутствует. В таком случае поля TYPE_LENGTH И DATA_LENGTH раВНЫ НуЛЮ. Идентификатор записи ID может быть любой строкой в виде URI. Его дли- на, записываемая в поле всегда выравнивается до величины, кратной 4. Кроме этих трех характеристик, запись может быть снабжена номером сво- ей версии и несколькими дополнительными полями. Номер версии — это версия спецификации DIME, сейчас это 1. Спецификация не определяет назначение дополнительных полей, но предписывает, чтобы у них были оп- ределены тип и длина. Тип всего сообщения DIME определен как MIME-тип application/dime. Сообщение DIME может входить с этим типом как одна из записей в дру- гое сообщение DIME. Первая запись DIME-сообщения помечается значением 1 флага (Message Begin), последняя запись — значением 1 флага ME (Message End). У сообще- ния, состоящего всего из одной записи, оба флага равны 1. Несколько записей могут содержать связанную информацию. Все такие за- писи должны быть одного и того же типа, у них должен совпадать номер версии. Такие записи помечаются флагом CF (Chunk Flag), у первой и про- межуточных записей этот флаг равен 1, у последней записи флаг CF равен о. Итак, сообщение DIME может содержать какие угодно записи, относящие- ся к Web-службам или совершенно другой природы. Правила применения к пересылке SOAP-посланий с дополнениями изложены в спецификации Ее можно посмотреть по адресу Разработка Web-служб средствами Java Сообщение DIME, содержащее SOAP-послание, состоит из первичного SOAP-послания и нескольких вторичных частей произвольной природы. Это могут быть изображения различных форматов, записи звука в различ- ных кодировках, программные коды, не обязательно определенные какими- нибудь типами MIME. Первой записью сообщения DIME должно быть первичное SOAP-послание. Значение поля TYPE первой записи для версии SOAP 1.1 должно совпадать с идентификатором пространства имен http://schemas.xmlsoap.org/soap/envelope/, для версии SOAP 1.2 тип первой записи — У первой записи может быть необязательный идентификатор, у следующих записей идентификатор должен быть обязательно. Он используется для ссылок из од- них записей сообщения на другие записи с помощью атрибута href. Спецификация DIME описывает только формат упаковки нескольких запи- сей в одно сообщение. Она ничего не говорит о способах пересылки полу- ченного сообщения. Единственное условие — при пересылке сообщения POST-методом протокола HTTP в поле заголовка следует ука- зывать ТИП application/dime. Из этого краткого описания видно, что сообщение DIME определено гораз- до точнее, чем multipart. Поля, записанные в начале каждой записи сообщения DIME, определяют тип и длину каждой записи. Это дает возможность программе, разбирающей сообщение, сделать необходимые проверки, не просматривая все сообщение целиком. Это экономит время и ресурсы компьютера. С другой стороны, такое точное описание сообщения DIME можно сделать только каким-нибудь инструментальным средством, автоматически создаю- щим сообщение. Не стоит и пытаться написать сообщение DIME вручную. Средства создания SOAP-посланий Несмотря на то, что технология Web Services еще очень молода, есть уже много средств создания SOAP-серверов и SOAP-клиентов. Эти средства можно разбить на четыре группы. 1. "Мастера", встроенные в IBM WebSphere Studio, Sun ONE Studio, Eclipse, IntelliJ IDEA, Microsoft Visual Studio Borland JBuilder и в другие ин- струментальные средства разработчика. Они позволяют несколькими щелчками по кнопке мыши создать Web-службу. Это хорошо, но создан- ные таким образом Web-службы редко удовлетворяют профессионала. 2. Наборы крупных классов и реализованных интерфейсов, автоматизи- рующих почти всю работу и требующих минимальной доводки: Apache SOAP, Apache Axis, GLUE, Microsoft SOAP Toolkit. Часто они уже Глава 3. Протокол SOAP и Web Services встроены или легко встраиваются в серверы приложений. Эти наборы удобны, когда надо быстро создать несложную Web-службу. 3. Наборы более мелких классов и нереализованных интерфейсов, требую- щих более тщательной сборки и значительных усилий от программиста: Sun SAAJ, JAXM, JAX-RPC, JAXR, IBM WSTK. Они дают больше свобо- ды и позволяют создавать самые разнообразные Web-службы. 4. Языки программирования: Java, Perl, C/C++, С#, VB.NET и другие. С их помощью можно создать все, что угодно, в том числе и Web-службы. Сейчас в их стандартные библиотеки включаются классы, облегчающие создание Web-служб. Средства первой группы не требуют какого-либо дополнительного описа- ния, кроме встроенной в них интерактивной справки. Средства четвертой группы описаны в других книгах, например, [9, 10]. В этой главе я опишу средства второй группы, в главах 6—7— средства третьей группы. Среди средств создания Web-служб второй группы в настоящее время наи- более активно развивается и широко распространяется Apache Axis. На мо- мент написания книги он только что вышел из чернового состояния, но уже встроен или легко встраивается во многие серверы приложений: IBM WebSphere, BEA WebLogic, Sun ONE Application Server. Его можно включить даже в состав Web-контейнеров, таких как Tomcat, Resin, JBoss. Кроме того, Axis свободно распространяется, доступны его исходные тексты. Поэтому мы рассмотрим подробнее работу с Axis. Работа с Axis Программный продукт Axis (Apache extensible Interaction System) разрабатываемый консорциумом W3C, пред- ставляет собой набор классов, большинство из которых реализуют интер- фейсы пакетов Sun SAAJ, JAXM, JAX-RPC. Эти интерфейсы мы рассмот- рим подробно в главе 6. Кроме того, в состав Axis входит небольшой отла- дочный SOAP-сервер — класс — и классы преобразования описаний WSDL в объекты Java и обратно. Установка Axis Установить Axis в ваш сервер приложений очень легко. Достаточно скопи- ровать каталог axis из каталога в каталог вашего сервера приложений или в другой каталог, в который устанавли- ваются сервлеты. После этого надо скопировать в каталог архив вашего любимого например, xerces.jar, и Разработка Web-служб средствами Java можно работать. Axis установлен как одно из Web-приложений, работаю- щих на вашем сервере. сервер приложений, наберите в браузере, запущенном на сервере, адрес http://localhost:8080/axis/ — и вы увидите начальную страничку Axis. Для дальнейшей работы с Axis необходимо, чтобы сервер приложений знал, где расположены файлы axis.jar, tt-bytecode.jar и xerces.jar. Для этого надо занести полные пути к этим фай- лам (к файлам, а не к каталогам, в которых они лежат) в переменную CLASSPATH или положить эти файлы в каталоги, известные серверу прило- жений. Обычно это один из каталогов lib, ext, common или endorsed сервера приложений. Запросы клиентов при работе с Axis принимает сервлет Убе- диться в его правильной работе можно, набрав в браузере, работающем на сервере, адрес http://locaIhost:8080/axis/servlet/AxisServlet. В окне браузера должна появиться строка "And now Some Services" и список некоторых Web- служб, установленных на сервере. В стандартную поставку Axis входит много примеров Web-служб. Посмотри- те каталог Вы увидите десяток подкаталогов, в которых лежат файлы с классами примерных Web-служб. Их исходные тексты лежат в каталоге Создание Web-службы для Axis Создать Web-службу, которая будет работать под управлением Axis, очень просто. Достаточно написать классы Java, реализующие Web-службу, дать файлу, содержащему исходные тексты этих классов, расширение и положить этот файл в каталог axis сервера приложений. Создадим Web-службу полезную для отладки и проверки пра- вильности передачи кириллицы. Она предоставляет одну Web-услугу getEcho (), просто возвращающую клиенту содержимое SOAP-запроса. Класс EchoService, содержащий метод getEcho о, приведен в листин- ге 3.14. Web-служба EchoService ' public class public String req){ return req; Глава 3. Протокол SOAP и Web Services 169 Назовем файл с содержимым листинга 3.14 EchoService.jws и положим его в каталог axis сервера приложений. Все, Web-служба готова. Не нужно ком- пилировать класс EchoService, Axis сделает это сам при первом запросе к Web-службе. Клиент Axis Клиентское приложение, обращающееся к Web-службе, выполняющейся под управлением Axis, написать нетрудно. В листинге 3.15 показан клиент Web-службы EchoService листинга 3.14. | Листинг Клиент Web-службы EchoService import import import public class EchoServiceClient{ public static void args) throws Exception) if 1)( "Usage: EchoServiceClient Service service = new Call call = String endpoint = String request = args[0]; String response = Разработка Web-служб средствами Java " + request); " + response); В листинге 3.15 использованы интерфейсы service и пакета Они реализованны классами, входящими в Axis. Мы познакомимся с этими интерфейсами в главе 6. Как видно из листинга 3.15, основную роль в полу- чении Web-услуги играет объект типа call. Он содержит адрес Web-службы endpoint и название Web-услуги getEcho. В него заносятся аргументы Web- услуги в виде массива объектов. В нашем простом примере массив аргумен- тов состоит только из одного элемента — строки request. Наконец, объект call методом invoke о возвращает объект, содержащий результат выполне- ния Web-услуги. Использование конфигурационного файла Возможность создать Web-службу, просто написав JWS-файл — большое достоинство Axis, но часто возникают ситуации, в которых этот способ не годится. Например, надо создать Web-службу из готовых классов Java, ис- ходные тексты которых отсутствуют, или задать какое-то особенное отобра- жение сложных типов данных для передачи их по протоколу SOAP, или создать Web-службу, независимую от Axis. В таких случаях Axis предлагает написать конфигурационный файл — дескриптор установки (Deployment Descriptor), описывающий Web-службу во всех подробностях. Мы будем на- зывать его DD-файлом. Потом, с помощью DD-файла надо выполнить уста- новку Web-службы в Web-контейнер. Конфигурационный DD-файл — это документ XML с корневым элементом Используемые в DD-файле имена элементов описаны в про- странстве имен с идентификатором http://xml.apache.org/axis/wsdd/. В DD-файлах часто записываются имена классов Axis. Эти имена описаны в пространстве имен с идентификатором http://xml.apache.org/axis/wsdd/ Обычно корневой элемент с описанием пространств имен вы- глядит так: Глава 3. Протокол SOAP и Web Services 171 Основную роль в описании играют элементы атрибут type кото- рых задает класс-обработчик, устанавливаемый в Axis, или ссылку на дру- гой, уже определенный элемент |