Возможность отправки и получения сообщения в стандартном формате, распознаваемом всеми взаимодействующими системами, лежит в основе технологии Web-сервисов. Как правило, этим форматом является SOAP. Сообщения SOAP можно создавать и отправлять вручную, но многие из необходимых шагов, например установка соединения или отправка сообщения, могут быть выполнены автоматически с помощью SAAJ (SOAP with Attachments API for Java) – API, появившегося в результате работы над программным интерфейсом для передачи сообщений XML (Java API for XML Messaging - JAXM). В данной статье рассматривается последовательность действий по созданию и отправке синхронных сообщений SOAP.
Весь процесс состоит из пяти шагов:
- создание соединения SOAP;
- создание сообщения SOAP;
- формирование сообщения;
- отправка сообщения;
- получение ответа.
SAAJ поставляется в составе пакета для разработки Web-сервисов Java (Java Web Services Developer Pack 1.2, см. Ресурсы). В пакет включены также Web-сервер Tomcat, благодаря которому вы можете развернуть собственный Web-сервис, и демонстрационные приложения.
Установка и конфигурирование Java Web Services Developer Pack 1.2 не представляет трудностей, если вы собираетесь отправлять сообщения через Web-сервер Tomcat. Если же подобно тому, как это делается в данной статье, вы хотите отправлять сообщения через отдельное приложение, то потребуются некоторые дополнительные действия.
- Скачайте JWSDP 1.2 по адресу: http://java.sun.com/webservices/downloads/webservicespack.html.
- Установите его согласно инструкциям.
- Если вы используете Java 1.4, то вам следует переопределить классы, относящиеся к XML, которые входят в поставку JWSDP 1.2. Создайте следующую директорию:
<JAVA_HOME>/jre/lib/endorsed
и скопируйте в нее все файлы из:<JWSDP_HOME>/jaxp/lib/endorsed
(переменные окруженияJAVA_HOMEиJWSDP_HOMEуказывают на директории установки Java и JWSDP соответственно). - Добавьте следующие файлы в classpath:
- <JWSDP_HOME>/saaj/lib/saaj-api.jar
- <JWSDP_HOME>/saaj/lib/saaj-impl.jar
- <JWSDP_HOME>/jwsdp-shared/lib/commons-logging.jar
- <JWSDP_HOME>/jwsdp-shared/lib/mail.jar
- <JWSDP_HOME>/jwsdp-shared/lib/activation.jar
- <JWSDP_HOME>/jaxp/lib/endorsed/dom.jar
- <JWSDP_HOME>/jaxp/lib/endorsed/xercesImpl.jar
- <JWSDP_HOME>/jaxp/lib/endorsed/sax.jar
- <JWSDP_HOME>/jaxp/lib/endorsed/xalan.jar
Теперь вы можете посылать сообщения из любой точки в вашей системе, используя собственное приложение.
Начнем с рассмотрения структуры самих сообщений. В общем случае SOAP-сообщение состоит из оболочки, разделенной на две главные части: заголовок и само сообщение. Несмотря на то, что использование этих частей остается на усмотрение конкретного приложения, сообщения должны иметь определенную XML-структуру, подобную показанной в листинге 1.
Листинг 1. Пример сообщения SOAP
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Header />
<SOAP-ENV:Body>
<ns1:getPrice xmlns:ns1="urn:xmethods-BNPriceCheck"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<isbn xsi:type="xsd:string">0672324229</isbn>
</ns1:getPrice>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope> |
В этом примере заголовок является пустым, и вся полезная часть заключена в теле сообщения. Данное сообщение используется для запроса цены на книгу.
Обратите внимание на структуру сообщения. Оболочка (элемент Envelope) содержит элементы Header и Body, причем все три принадлежат пространству имен http://schemas.xmlsoap.org/soap/envelope/. Приложение отправляет сообщения, используя объект SOAPConnection.
Установка соединения и создание сообщения
Первым шагом является создание экземпляра класса соединения и установка самого соединения (листинг 2).
Листинг 2. Создание соединения
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConnection;
public class SOAPTip {
public static void main(String args[]) {
try {
//Сначала создаем соединение
SOAPConnectionFactory soapConnFactory =
SOAPConnectionFactory.newInstance();
SOAPConnection connection =
soapConnFactory.createConnection();
//Закрываем соединение
connection.close();
} catch(Exception e) {
System.out.println(e.getMessage());
}
}
} |
Приложение может отправлять сообщения SOAP непосредственно через класс SOAPConnection, который теперь включен в пакет SAAJ, или с использованием провайдера сообщений, являющегося частью пакета JAXM. Объект SOAPConnection создается с помощью фабрики.
Фабрика также используется для создания самого сообщения (листинг 3).
Листинг 3. Создание сообщения
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPBody;
public class SOAPTip {
public static void main(String args[]) {
try {
//Сначала создаем соединение
SOAPConnectionFactory soapConnFactory =
SOAPConnectionFactory.newInstance();
SOAPConnection connection =
soapConnFactory.createConnection();
//Затем создаем сообщение
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage message = messageFactory.createMessage();
//Создаем объекты, представляющие различные компоненты сообщения
SOAPPart soapPart = message.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
SOAPBody body = envelope.getBody();
//Закрываем соединение
connection.close();
} catch(Exception e) {
System.out.println(e.getMessage());
}
}
} |
Сначала с помощью объекта MessageFactory создается собственно сообщение. В этот момент оно уже включает в себя разделы envelope и header, но они пока пусты. Объект SOAPPart содержит envelope, в который, в свою очередь, включено тело сообщения. Далее объявляются переменные, содержащие все необходимые ссылки, в частности, SOAPBody.
Далее необходимо заполнить данными тело сообщения (объект SOAPBody), как показано в листинге 4.
Листинг 4. Формирование тела сообщения
...
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPElement;
public class SOAPTip {
public static void main(String args[]) {
try {
...
//Создание объектов, представляющих собой части сообщения
SOAPPart soapPart = message.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
SOAPBody body = envelope.getBody();
//Формирование тела сообщения
//Создание главного элемента с учетом пространства имен
SOAPElement bodyElement =
body.addChildElement(envelope.createName("getPrice" ,
"ns1",
"urn:xmethods-BNPriceCheck"));
//Добавление содержимого
bodyElement.addChildElement("isbn").addTextNode("0672324229");
//Сохранение сообщения
message.saveChanges();
//Проверка созданного сообщения
System.out.println("\nREQUEST:\n");
message.writeTo(System.out);
System.out.println();
//Закрытие соединения
connection.close();
} catch(Exception e) {
System.out.println(e.getMessage());
}
}
} |
Тело сообщения SOAP представляет собой обыкновенный XML-элемент, в который можно помещать вложенные элементы, такие как getPrice. Далее можно добавить элемент isbn и соответствующий ему текст. Все делается так же, как и в случае любого элемента DOM.
SAAJ также позволяет напрямую создать объект SOAPPart-сообщения из внешнего файла. Например, если XML-содержимое сообщения, приведенного в листинге 1, содержится в файле prepped.msg, то к нему можно обратиться вместо ручного создания сообщения (листинг 5).
Листинг 5. Создание сообщения из внешнего файла
...
import javax.xml.soap.SOAPElement;
import java.io.FileInputStream;
import javax.xml.transform.stream.StreamSource;
public class SOAPTip {
public static void main(String args[]) {
...
//Создание объектов, представляющих различные части сообщения
SOAPPart soapPart = message.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
SOAPBody body = envelope.getBody();
//Формирование сообщения
StreamSource preppedMsgSrc = new StreamSource(
new FileInputStream("prepped.msg"));
soapPart.setContent(preppedMsgSrc);
//Сохранение сообщения
message.saveChanges();
...
}
} |
Класс StreamSource обычно используется при преобразованиях XSL, но в данном случае с его помощью просто открывается файловый поток ввода FileInputStream. В результате у нас получилось готовое к отправке сообщение.
При работе с синхронными сообщениями SOAP, отправка и получение ответа выполняются за один шаг (листинг 6).
Листинг 6. Отправка сообщения
...
public class SOAPTip {
public static void main(String args[]) {
...
//Проверка созданного сообщения
System.out.println("\nREQUEST:\n");
message.writeTo(System.out);
System.out.println();
//Отправка сообщения и получение ответа
//Установка адресата
String destination =
"http://services.xmethods.net:80/soap/servlet/rpcrouter";
//Отправка
SOAPMessage reply = connection.call(message, destination);
//Закрытие соединения
connection.close();
...
}
} |
Сообщение отправляется в момент вызова метода call(), который принимает в качестве аргументов само сообщение и адрес назначения. В качестве ответа метод возвращает другой объект SOAPMessage. В более ранних версиях JAXM адрес назначения должен был быть экземпляром класса Endpoint или URLEndpoint, но в текущей версии адресом может быть объект любого типа. В данном примере используется Web-сервис под названием "Узнай цену на книгу" ("Book price checker"), размещенный на сервере XMethods и возвращающий цену на книгу, ISBN которой содержится в запросе.
Метод call() блокирует выполнение программы до момента получения ответа в виде объекта SOAPMessage.
Полученный объект типа SOAPMessage, ссылка на который хранится в переменной reply, также является сообщением SOAP, и его структура идентична отправленному сообщению. Как и любое XML-сообщение, его можно трансформировать с помощью XSLT. SOAP позволяет выполнить XSLT-преобразование напрямую, как показано в листинге 7.
Листинг 7. Чтение полученного ответа
...
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamResult;
public class SOAPTip {
public static void main(String args[]) {
try {
...
//Отправка сообщения
SOAPMessage reply = connection.call(message, destination);
//Проверка полученного ответа
System.out.println("\nRESPONSE:\n");
//Создание XSLT-процессора
TransformerFactory transformerFactory =
TransformerFactory.newInstance();
Transformer transformer =
transformerFactory.newTransformer();
//Получение содержимого ответа
Source sourceContent = reply.getSOAPPart().getContent();
//Задание выходного потока для результата преобразования
StreamResult result = new StreamResult(System.out);
transformer.transform(sourceContent, result);
System.out.println();
//Закрытие соединения
connection.close();
...
}
} |
Сначала, как и всегда при использовании XSLT, необходимо создать объект Transformer. В данном случае нам просто надо вывести содержимое сообщения, поэтому таблица стилей не используется. Под содержимым понимается SOAP-часть сообщения, а не все сообщение, в котором могут еще содержаться вложения. Перед обработкой можно также разделить оболочку и тело сообщения. Содержимое выводится в System.out (см. рисунок 1), но в принципе результат трансформирования может выводиться в любой доступный поток вывода. Само преобразование происходит обычным образом.
Рисунок 1. Запрос и ответ в SOAP
В нашем простом примере сообщение просто выводится в стандартный поток вывода, но с таким же успехом можно было получить нужную информацию из документа XML. Кроме того, хотя в данной статье демонстрируется синхронная отправка и получение сообщений, интерфейс JAXM, который можно скачать отдельно, позволяет использовать провайдер сообщений, обеспечивающий асинхронную доставку с помощью объекта ProviderConnection вместо SOAPConnection. Провайдер хранит сообщение, пока оно не будет успешно доставлено.
JAXM также поддерживает работу с профилями, которые облегчают создание специализированных сообщений SOAP, таких как SOAP-RP или ebXML.
- Оригинал статьи: "Tip: Send and receive SOAP messages with SAAJ". (EN)
- Следите за работой над различными рекомендациями, относящимися к Web-сервисам, на сайте W3C. (EN)
- Попробуйте в деле SAAJ, являющийся частью JWSDP 1.2 - пакета для разработки Web-сервисов на Java. (EN)
- Скачайте IBM WebSphere Studio Application Developer – легкую в использовании, интегрированную среду для разработки, сборки, тестирования и развертывания Web-сервисов. (EN)
- Обратитесь к разделам по XML и Web-сервисам на сайте developerWorks, которые содержат множество материалов по этим темам. Кроме того, зайдите на страницу, где перечислены статьи-советы по XML, опубликованные к данному моменту времени. (EN)
-
Сертификация по XML корпорации IBM: Узнайте, как стать сертифицированным разработчиком IBM в области XML и связанных с ним технологий. (EN)
Никлас Чейз (Nicholas Chase) участвовал в разработке Web-сайтов для таких компаний, как Lucent Technologies, Sun Microsystems, Oracle и Tampa Bay Buccaneers. Ник успел побывать школьным учителем физики, редактором электронного научно-фантастического журнала, инженером в области мультимедиа, инструктором по Oracle и главным инженером в интерактивной коммуникационной компании. Он является автором нескольких книг, в том числе XML Primer Plus (Sams).