Главная » Java, Web, XML » Создание SOAP-послания

0

Интерфейсы Java, входящие в пакет javax.xml. soap, описывают SOAP- послание и его элементы. Для представления элементов XML, составляющих SOAP-послание, применяется модель дерева DOM (см. главу 7). Поэтому во главе всех интерфейсов, описывающих послание, стоит интерфейс Node.

Узел дерева элементов Node

Методы интерфейса Node традиционны для работы с узлом дерева:

?     public string getvalue () — возвращает ссылку на значение первого узла-потомка, если оно представимо в виде строки; в противном случае возвращается null;

? public SOAPElement getParentElement () — возвращает ССЫЛКУ на узел- предок данного узла или null, если предка нет:

?     public void setParentElement (SOAPElement parent) — устанавливает новый узел parent в качестве предка данного узла;

?     public void detachNode () — удаляет узел из дерева.

Элемент послания SOAPElement

Интерфейс Node расширен интерфейсом SOAPElement, определяющим в общих чертах элементы XML, составляющие SOAP-послание. Его методы addxxx () наполняют создаваемый элемент содержимым:

?    public SOAPElement addAttribute(Name name, String value) — добавляет атрибут name со значением value в открывающий тег данного элемента; возвращает ссылку на обновленный элемент с добавленным атрибутом;

•          public SOAPElement addChildElement (Name name) — создает НОВЫЙ элемент с именем name, вложенный в данный элемент, и возвращает ссылку на него;

•          public SOAPElement addChildElement(SOAPElement element).— добавляет элемент element, вложенный в данный элемент, и возвращает ссылку на него же;

•         public SOAPElement addChildElement(String localName) — создает НОВЫЙ элемент с именем localName без префикса, вложенный в данный элемент, и возвращает ссылку на него;

•         public SOAPElement addChildElement(String localName, String prefix) — создает новый элемент с расширенным именем prefix .-localName, вложенный в данный элемент, и возвращает ссылку на него;

? public SOAPElement addChildElement (String localName, String

prefix, string uri) — создает новый элемент с расширенным именем prefix: localName и идентификатором пространства имен uri, вложенный в данный элемент, и возвращает ссылку на него;

public SOAPElement                                           prefix, String

uri) — добавляет атрибут xmlns со значением uri к открывающему тегу данного элемента и возвращает ссылку на измененный элемент;

•          public SOAPElement addTextNode (String text) — добавляет тело элемента в виде строки text и возвращает ссылку на измененный элемент;

•          public void setEncodingStyle (String encStyle) — добавляет атрибут encodingstyle со значением                к открывающему тегу данного элемента.

Остальные МЯСДЫ ВИДа getXxx () , removeXxx () интерфейса SOAPElement возвращают различные сведения об элементе и удаляют различные части элемента.

Открывающий тег элемента XML

Интерфейс Name, используемый в перечисленных выше методах, определяет имя элемента XML с префиксом или без префикса и с идентификатором Пространства имен. Его методы getLocalName (), getPrefix(), (),       () возвращают составные части имени XML в

виде строки типа string.

Основные элементы SOAP-послания

Интерфейс SOAPElement расширен интерфейсами, описывающими корневой элемент SOAP-послания <Е we lope > и вложенные в него элементы <Header> И <Body>. Это интерфейсы SOAPEnvelope, SOAPHeader, SOAPBody. Блоки заголовка описывает интерфейс SOAPHeaderElement, а содержимое ПОСЛЙИЯ — интерфейс SOAPBodyElement.

Интерфейс SOAPBodyElement расширен интерфейсом SOAPFault, описывающим элемент <Fault> — единственный элемент, вложенный в элемент <Body> и определенный в спецификации SOAP. Элементы, вложенные в <Fault>, описаны интерфейсом SOAPFaultElement, а ЭЛемеНТ <detail> специально описан интерфейсом Detail. Элементы, вложенные в <detail>, описаны интерфейсом DetailEntry.

Вся зла иерархия интерфейсов показана на рис. 6.1.

Рис. 6.1. Иерархия интерфейсов SAAJ

Корневой элемент SOAPEnvelope

Интерфейс SOAPEnvelope добавляет к методам интерфейса SOAPElement следующие методы, создающие элементы SOAP-послания:

•          public SOAPHeader addHeader (} — добавляет К SOAP-ПОСЛаниЮ пустой заголовок — элемент <Header> — и возвращает ссылку на него;

•          public SOAPHeader getHeader () — формирует элемент <Header> И ВОЗвращает ссылку на него;

•          public SOAPBody addBody () — добавляет к SOAP-посланию пустой элемент <Body> и возвращает ссылку на него;

? public SOAPBody getBody () — возвращает ссылку на созданный этим же методом пустой элемент <Body>;

•          public Name createName (String localName) — создает элемент XML С именем localName без префикса;

•          public Name createName (String localName, String prefix, String uri) — создает элемент XML с расширенным именем prefix: localName и идентификатором пространства имен uri.

Заголовокпослания SOAPHeader

Интерфейс SOAPHeader, в свою очередь, описывает метод public SOAPHeaderElement addHeaderElement(Name name),

создающий и добавляющий блок заголовка с именем name. Кроме этого метода в интерфейс входит еще метод

public Iterator examineHeaderElements (String actor),

возвращающий итератор для перебора всех блоков заголовка, предназначенных для роли actor, и метод

public Iterator extractHeaderElements(String actor),

удаляющий из заголовка блоки, предназначенные для роли actor, и возвращающий итератор для их перебора.

Содержимое послания SOAPBody

Интерфейс SOAPBody содержит метод

public SOAPBodyElement addBodyElement (Name name) ,

добавляющий к содержимому SOAP-послания произвольный элемент, и методы

public SOAPFault addFault(), public SOAPFault getFault(), public boolean hasFault (),

работающие с элементом                вкладываемым в элемент <Body> для от

правки сообщения об ошибке.

Как видите, интерфейсы, входящие в пакет SAAJ, детально описывают структуру SOAP-послания и содержат все методы для создания и изменения его элементов.

Послание SOAPMessage

Пакет SAAJ позволяет создавать SOAP-послания с дополнениями, следуя спецификации "SOAP с дополнениями", с которой мы познакомились в главе 3. Для этого в его состав введен абстрактный класс SOAPMessage, методы которого создают, добавляют или удаляют дополнительные части послания. Начальная часть SOAP-послания с дополнениями, содержащая собственно SOAP-послание, описана абстрактным классом soAPPart, а сами дополнения определены в абстрактном классе AttachmentPart. Заголовок каждой части добавляется и удаляется методами класса        а каждое поле

заголовка — методами класса MimeHeader.

Таким образом, пакет SAAJ составлен из интерфейсов и абстрактных классов, требующих реализации. В наборе Sun WSDP такая реализация сделана классами, упакованными в архив saaj-rijar. Реализация сильно зависит от операционной среды, в которой будет работать система SAAJ. Поэтому у классов, реализующих пакет SAAJ, почти нет конструкторов, их экземпляры создаются через фабричные классы и их методы. Фабричные классы MessageFactory, SOAPFactory И SOAPConnectionFactory ВХОДЯТ В СОСТЭВ SAAJ .

Процесс создания SOAP-послания

Формирование SOAP-послания удобно начать с создания экземпляра класса SOAPMessage. Для ЭТОГО применяем метод createMessage() класса MessageFactory, предварительно создав объект класса MessageFactory его же статическим методом newlnstance (): MessageFactory mf = MessageFactory.newlnstance () ; SOAPMessage smsg = mf .createMessage () ;

Далее из объекта smsg, представляющего SOAP-послание с дополнениями, выделяем начальную часть soapPart, содержащую пока еще пустое SOAP- послание:

SOAPPart soapPart =

Потом создаем корневой элемент SOAP-послания:

SOAPEnvelope env = soapPart. getEnvelope ()

После этого уже сформирован элемент <SOAP-ENV:Envelope

xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> c/SOAP-ENV:Envelope>

В то время, когда были написаны эти строки, пакет SAAJ 1.1 формировал SOAP-послания версии SOAP 1.1, поэтому он записал старый идентификатор пространства имен http://schemas.xmlsoap.org/soap/envelope/.

Затем формируем заголовок <Header>:

SOAPHeader header = env.getHeader О;

В результате появляется элемент <SOAP-ENV:Header> </SOAP-ENV:Header>

Он пуст, но уже вложен в элемент <Envelope>. Аналогично формируем элемент <Body>:

SOAPBody tody = env.getBody () ;

Получаем пустой элемент <SOAP-ENV:Body> c/SOAP-ENV:Body>

вложенный в элемент <Envelope>.

Если заголовок <Header> нам не нужен, то его можно удалить: header.detachNode() ;

После этого можно заполнять SOAP-послание нужной информацией. Например, мы хотим обратиться к методу

public String getEcho(String request) следующим образом:

String response = echoservice.getEcho("Привет!"). Для этого сначала создаем элемент

<m: getEchoxmlns :m="http://some. com/names"></m:getEcho> методом createName ():

Name element = env.createName ("getEcho", "m", "http: / / some. com/names ");

и помещаем элемент <getEcho> в элемент <Body>:

SQAPBoGyElement ge = body. addBodyElement (element) ; Затем создаем элемент

<request>npKBeT!</request>

и вкладываем его в элемент <getEcho>. Это выполняется в следующих трех строчках:

Name name = env.createName ("request") ; SQAPElement req = ge.addChildElement (name) ; req.addTextNode("Привет!") ;

Все, SOAP-послание готово и выглядит так:

<SOAP-ENV:Envelope

xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

<SOAP-ENV:Body>

<m: getEcho xmlns :m="http: //some. com/names"> <request>npHBeT

!</request>

</m:getEcho> </SOAP-ENV:Body> </SOAP-ENV:Envelope>

Отправка SOAP-послания и получение ответа

Теперь надо отправить SOAP-послание smsg. Для этого надо установить соединение с SOAP-сервером. Сначала подготавливаем объект класса SOAPConnection:

SOAPConnectionFactory scf =

SOAPConnectionFactory.newInstance(); SOAPConnection con = scf .createConnection();

Потом определяем адрес Web-службы в виде объекта класса URL ИЛИ объекта класса Endpoint, например:

URL endpoint =

new URL("http://some.com/services/EchoService");

Все готово. Теперь одним махом отправляем SOAP-послание и получаем ответ:

SOAPMessage response = con.call(smsg, endpoint); После получения ответа можно закрыть соединение: con.close();

или посылать следующее сообщение.

Как видно из приведенного выше описания, для работы метода call о необходимо, чтобы SOAP-сервер находился на связи, иначе клиентская программа зависнет в ожидании ответа. Как говорят, пакет                          обеспечивает синхронную работу клиента с Web-службой. Такой способ сетевого взаимодействия часто называют "point-to-point", сокращенно "Р2Р".

После получения от SOAP-сервера ответа response, надо его разобрать и выделить полезную информацию. Для этого последовательно выделяем отдельные части ответного SOAP-послания. Сначала выделяем начальную часть послания:

SOAPPart sp = response. getSOAPPart () ;

Затем из начальной части выделяем SOAP-послание:

SOAPEnvelope respEnv = sp.getEnvelopeO ;

Потом вьщеляем содержимое послания: SOAPBody respEody = respEnv. getBody ()

Из элемента <Body>, представленного объектом respBody, выбираем все вложенные элементы. Сначала получаем их итератор:

Iterator it = respBody.getChildElements();

Нас интересует только первый элемент, содержащий ответ сервера. Получим его:

SOAPBodyElement bodyElement = (SOAPBodyElement)it.next();

Вьщеляем содержимое ответа:

String echo = bodyElement.getValue();

и выводим в стандартный вывод клиентской машины:

System.out.println("Ответ сервера: " +echo);

Все сделано, мы воспользовались услугами Web-службы. В листинге 6.1 приведен полный текст синхронного клиента Web-службы.

Листинг 6.1. Клиент Web-службы, созданный средствами SAAJ

import

import java.util.*;

import

public class ClientSAAJ{

public static void main(String[] args) { try{

=

;

=

SOAPPart soapPart = smsg.getSOAPPart(); SOAPEnvelope env = soapPart.getEnvelope();

SOAPHeader header = env.getHeader(); SOAPBody body = env.getBody(); header.detachNode() ;

Name element = env.createName(

"getEcho", "m", "http://some.com/names");

SOAPBodyElement ge =

body.addBodyElement(element);

Name name = env.createName("request"); SOAPElement req = ge.addChildElement(name); req.addTextNode("Привет!") ;

SQAPConnectionFactory scf =

SOAPConnectionFactory.newInstance(); SQAPConnection con = URL endpo int =

new URL("http://some.com/services/EchoService"); SOAPMessage response = con.call(smsg, endpoint);

con.close();

SQAPPart sp =

SQAPEnvelope respEnv = sp.getEnvelope(); SOAPBody respBody = respEnv.getBody();

Iterator it

SOAPBodyElement bodyElement =

(SOAPBodyElement)it.next();

String echo =

System.out.print("Ответ сервера: " + echo); }catch(Exception e) { System.err.println(e) ;

}

}

}

с дополнениями

Как сказано выше, объект класса SOAPMessage содержит SOAP-послание с дополнениями. Пока мы использовали только начальную часть послания — объект класса soAPPart. В этом разделе добавим к посланию дополнительные части.

Каждое дополнение формируется методами абстрактного класса AttachmentPart. Создать экземпляр этого класса можно одним из трех методов класса SOAPMessage.

Первый метод

AttachmentPart ар = smsg. createAttachmentPart () ;

создает пустую дополнительную часть ар. После создания, экземпляр ар надо заполнить содержимым, применяя методы класса AttachmentPart.

После полного оформления дополнения ар, о чем речь пойдет чуть ниже, его надо добавить к посланию следующим методом:

smsg.addAttachmentPart(ар);

Второй метод создания экземпляра класса AttachmentPart: public AttachmentPart createAttachmentPart ( Object content, String contentType);

формирует дополнительную часть с уже готовым, предварительно определенным, содержимым content, MIME-тип которого, записываемый в поле заголовка создаваемой дополнительной части, равен contentType. Например:

AttachmentPart ар = smsg. createAttachmentPart ( "Это простой плоский ASCII-текст дополнения", "text/plain; charset=windows-1251") ;

smsg.addAttachmentPart(ар);

Третий метод создания дополнительной части

public AttachmentPart

j avax.activation.DataHandler handler);

использует дескриптор handler данных, полученных из файла или с какого- то адреса URL с помощью механизма Java Activation Framework [10]. Например:

URL url = new URL ("http://some.com/images/myface. jpg") ;

AttachmentPart ap =

93ак. 748

smsg.createAttachmentPart(new DataHandler(uri)); smsg.addAttachmentPart(ap);

Итак, если содержимое дополнительной части уже готово и не нужны дополнительные заголовки, то дополнение создается одним действием. Посмотрим, какими методами обладает класс                         для того чтобы создать нестандартное дополнение к SOAP-посланию.

Класс AttachmentPart

Напомним, что каждая дополнительная часть послания, оформленного по спецификации "SOAP с дополнениями" (см. главу 3), записывается после Дополнительная часть состоит из необязательного MIME-заголовка, состоящего из нескольких полей, пустой строки и произвольного содержимого. Среди полей заголовка наиболее важно поле content-Type, определяющее MIME-тип содержимого.

Создание дополнения

Несколько методов класса AttachmentPart формируют дополнительной части SOAP-послания.

Поле name MIME-заголовка со значением value добавляется к заголовку дополнительной части методом

public void addMimeHeader (String name, String value) ;

Ввиду особой важности поля Content-Type, для его создания есть специальный метод

public void setContentType (String value) ;

Еще два поля — Content-Id и Content-Location — добавляются к заголовку собственными методами

public void setContentld(String value); public void setContentLocation(String value);

Если поля заголовка уже определены, то эти три метода                      меняют

их значения. Заменить старое значение любого поля name заголовка новым значением value можно методом

public void setMimeHeader (String name, String value) ;

Этот же метод определяет новое поле заголовка, если оно еще не было создано.

Содержимое content дополнения включается в методом

public void setContent (Object content. String contentType);

Кроме ТОГО), ЗЮТ метод записывает значение contentType ПОЛЯ Content- Type.

Разбор дополнения

Следующие методы облегчают SOAP-серверу разбор полученного от клиента послания.

Выделить все дополнительные части из полученного послания класса SOAPMessage МЖЮ методом

public Iterator getAttachments();

класса SOAPMessage, возвращающим итератор, с помощью которого можно перебрать все дополнительные части послания.

Еще один метод того же класса

public Iterator getAttachments(MimeHeaders headers);

возвращает итератор всех дополнительных частей с полями заголовков, занесенными В объект headers.

Получив итератор одним из этих двух методов, обычным образом выбираем дополнение:

Iterator it = smsg.getAttachments();

while (it.hasNext ()) {

AttachmentPart ap = (AttachmentPart)it.next();

// Обработка дополнительной части ар послания

}

Выбрав нужное дополнение, разбираем его и выделяем полезную информацию. Для этого в классе AttachmentPart есть несколько методов доступа getxxx (). Перечислим их.

Содержимое дополнительной части можно получить методом

public Object getContent();

Размер содержимого в байтах возвращает метод

public int getSize();

Перебрать значения всех полей заголовка можно, получив их итератор методом

public Iterator getAHMimeHeaders () ;

Значения всех полей с именем name в виде массива строк возвращает метод public     name);

Метод

public Iterator getMatchingMimeHeaders(String[] names);

возвращает итератор всех полей заголовка, чьи имена занесены в массив

names.

Метод

public Iterator getNonMatchingMimeHeaders(String[] names);

решает двойственную задачу — возвращает итератор всех полей заголовка,

чьи имена не совпадают с именами, перечисленными в массиве names.

Наконец, значения трех полей заголовка: content-Type,                                 и

Content-Location можно получить специальными методами

public String getContentType () ; public String getContentld () ; public String getContentLocation () ;

Удаление частей дополнения

Удалить содержимое дополнения можно методом public void clearContent () ; Все поля заголовка дополнения удаляет метод public void removeAHMimeHeaders () ; Следующий метод

public void removeMimeHeader (String name); удаляет все поля заголовка с именем name.

В листинге 6.2 приведен пример формирования и отправки SOAP-послания с дополнением — страничкой HTML.

! Листинг 6.2. Послание с дополнениями

import javax.xml.soap.*; import javax.xml.messaging.*; import javax.activation.*;

import java.util.*; import java.net.URL;

public class ClientSAAJAttach{

public static void main(String[] args)(

try{

MessageFactory mf = MessageFactory.newInstanceO;

SOAPMessage smsg = mf.createMessage();

SOAPPart soapPart = smsg.getSOAPPart() ; soAPEnvelope env = soapPart.getEnvelope();

SOAPHeader header = env.getHeader(); SOAPBody body = env.getBody(); header.detachNode();

Name element = env.createName(

"getEcho", "m", "http://some.com/names");

SOAPBodyElement ge

body.addBodyElement(element);

Name name

SOAPElement req = ge.addChildElement(name); req.addTextNode("Привет!");

URL url = new URL("http://localhost:8080/data/info.html");

AttachmentPart ap =

smsg.createAttachmentPart(new DataHandler(url)); ap.setContentType("text/html") ; smsg.addAttachmentPart(ap);

SOAPConnectionFactory scf =

SOAPConnectionFactory.newInstance() ;

SOAPConnection con =

URLEndpoint endpoint = new

SOAPMessage response = con.call (smsg, endpoint);

con.close();

SOAPPart sp = response.getSOAPPart();

SQAPEnvelope respEhv = sp. getEnvelope () ; SCAPBody respBody = respEnv.getBody();

Iterator it = respBody.getChildElements();

SOAPBodyElement bodyElement =

(SOAPBodyElement)it.next();

String echo = bodyElement.getValue();

System.out.print("Ответ сервера: " + echo);

}catch(Exception e) { System.err.println(e);

}

}

}

Сообщение об ошибке

Как уже говорилось в главе 3, заметив ошибку в полученном послании, SOAP-сервер отправляет сообщение, содержащее в теле ответного SOAP- послания всего один элемент <Fault>, вложенный в элемент <Body>. В пакете SAAJ есть интерфейс soAPFauit, описывающий элемент <Fault>.

Интерфейс SOAPFault

Напомним, что в элемент <Fault> версии SOAP 1.1 можно вложить элементы <faultcode>, <faultstring>, <actor> И <detail>. Они создаются следующими методами, описанными в интерфейсе soAPFauit:

public void setFaultCode (String faultCode); public void setFaultString (String faultString); public void setFaultActor (String faultActor); public Detail     ;

Остальные методы интерфейса soAPFauit предназначены для разбора клиентом полученного от сервера сообщения об ошибке:

public String getFaultCode() ; public String getFaultString (); public String public Detail getDetail();

Как видно из этого описания, метод                                создает пустой элемент

<detail>. Его надо наполнить содержимым. Это выполняется методом

public DetailEntry addDetailEntry (Name name);

описанным в интерфейсе Detail.

Посмотреть при разборе содержимое элемента <detail> можно при помощи итератора, полученного вторым методом интерфейса Detail:

public Iterator getDetailEntries(); Все эти действия приведены в листинге 6.3.

Листинг 6.3. Пример создания и разбора сообщения об ошибке

import j avax. xml. soap. *; import java.util.*;

public class

public static void main(String[] args)( try{

MessageFactory mf = MessageFactory.newInstance(); SOAPMessage smsg = mf.createMessage();

SOAPEnvelope env =

smsg.getSOAPPart().getEnvelope(); SOAPBody body = env.getBody();

SOAPFault fault =

fault.setFaultCode("Client");

fault.setFaultString(

"Послание неправильно оформлено"); fault.setFaultActor("http://some.com/SomeService"); Detail detail = fault.addDetail();

Name entryNamel = env.createName(

"comment", "nsl", "http://some.com/comments");

DetailEntry entry =

entry.addTextNode("He задано значение параметра");

Name entryName2 = env.createName(

"confirmation", "ns2", "http://some.com/confirm");

DetailEntry entry2 =

entry2.addTextNode("Неверный код отправителя"); smsg.saveChanges();

// Проверим созданное послание. if

fault = String code =

String s = fault.getFaultStringO;

String actor =

System, out. println ("Код ошибки: " + code); System.out.println("Разъяснение: " + s) ;

if (actor != null)

замечена " + actor);

detail =

if (detail != null){

System.out.println("Детали: " ) ;

Iterator it = detail.getDetailEntries(); while (it.hasNext()){

entry = (DetailEntry)it.next(); String value = entry.getValue(); System.out.println(value);

}

}

}

}catch(Exception e) { System.out.println(e);

}

}

}

Литература:

Хабибуллин И. Ш. Разработка Web-служб средствами Java. — СПб.: БХВ-Петербург, 2003. — 400 с: ил.

По теме:

  • Комментарии