Программные интерфейсы JAX-WS Сlient API в Web Services Feature Pack for WebSphere Application Server V6.1: Часть 1. Создание клиента Dispatch

Эта серия статей знакомит разработчиков с JAX-WS 2.0, новой моделью программирования, поддерживаемой в Web Services Feature Pack for WebSphere Application Server V6.1. Часть 1 посвящена созданию клиента Dispatch с использованием программных интерфейсов JAX-WS Сlient API.

Дэн Седов, старший инженер-программист, I.B.M.

Дэн Седов (Dan Sedov) - фотографияДэн Седов (Dan Sedov) работает старшим инженером-программистом в IBM Software Group; занимается тестированием функций компонента Web Services Feature Pack сервера WebSphere Application Server. Последние 2 года Дэн является членом группы разработки WebSphere, занимающейся созданием и тестированием первого Web Services Feature Pack. Он работает над созданием и автоматизацией тестов механизма Web-сервисов JAX-WS. С ним можно связаться по адресу sedov@us.ibm.com.



Нихил Такер, старший инженер-программист, IBM

Нихил Такер (Nikhil Thaker) - фотографияНихил Такер (Nikhil Thaker) работает старшим инженером-программистом IBM Software Group в группе разработки WebSphere, занимающейся созданием Web Services Feature Pack. Он имеет более чем 9-летний опыт работы в области Enterprise Application Integration (интеграция корпоративных приложений), а в последние 2 года основное внимание уделяет Web-сервисам. Нихил работал с различными клиентами IBM в качестве ИТ-специалиста IBM Global Services по Enterprise Application Integration. Имеет опыт работы в автомобильной отрасли, здравоохранении, телекоммуникациях и сфере коммунальных услуг. С ним можно связаться по адресу nikhil.v.thaker@us.ibm.com.



27.12.2011

Введение

WebSphere Application Server V6.1 Feature Pack for Web Services расширяет возможности сервера WebSphere Application Server V6.1 по асинхронной, надежной и безопасной отправке сообщений Web-сервисов, делая упор на совместимость с другими производителями. Feature Pack обеспечивает поддержку новых стандартов Web-сервисов, включая:

  • Web Services Reliable Messaging (WS-RM).
  • Web Services Addressing (WS-Addressing).
  • SOAP Message Transmission Optimization Mechanism (MTOM).
  • Web Services Secure Conversations (WS-SC).

Он также поддерживает следующие основанные на стандартах модели программирования:

  • Java API for XML Web Services (JAX-WS 2.0).
  • Java Architecture for XML Binding (JAXB 2.0).
  • SOAP with Attachments API for Java (SAAJ 1.3).
  • Streaming API for XML (StAX 1.0).

Данная серия посвящена программным интерфейсам JAX-WS 2.0 Сlient API.

Новый программный интерфейс Dispatch (отправка), представленный в JAX-WS, поддерживает полностью динамический вызов сервиса. Для создания клиента не нужны документы в форматах WSDL или XML Schema, а также никакая иная информация о формате сообщения. Платой за подобную гибкость является то, что разработчик должен хорошо знать детали протокола SOAP и базовые интерфейсы создания сообщений, такие как DOM или SAAJ. Ниже приведены примеры ситуаций, в которых может потребоваться использование отправок:

  • Сценарии обмена документами, где важна динамическая природа отправок - например, когда текущее сообщение представляет собой выходные данные внешнего процесса, такие как файл из внешней системы или результат XSLT-преобразования. В этом случае отправка используется для предоставления SOAP-пакета, передачи сообщения и возврата ответа без взаимодействия с самим сообщением.
  • Необходимость взаимодействия с более старыми сервисами, несовместимыми с WS-I, например, с сервисами, поддерживающими формат RPC-encoded.
  • Необходимость использования технологии связывания данных, отличной от JAXB. JAX-WS строится на тесной интеграции с JAXB 2.0. Несмотря на то, что в JAX-WS нет прямой поддержки других видов связывания, при написании этой статьи мы рассмотрели ряд сценариев, в которых нужно использовать другую технологию связывания данных, например bean-компоненты Castor или XML.
  • Ситуации, когда отказ от использования SOAP-протокола дает особые преимущества: отправки поддерживают XML/HTTP-связывание для вызова конечных точек, которые обмениваются необработанными XML-документами, основанными на структурах, определенных приложением.

В статье приводятся:

  1. Краткий обзор JAX-WS.
  2. Пример клиента Dispatch JAX-WS.
  3. Примеры различных клиентских программных интерфейсов для обработки сообщений Web-сервисов.

Читатели должны хорошо разбираться в XML, SOAP, WSDL и Web-сервисах.


Обзор JAX-WS 2.0

JAX-WS 2.0 - это новый программный интерфейс Java для разработки Web-сервисов. Он построен на предыдущей модели программирования JAX-RPC с многочисленными усовершенствованиями. Некоторые преимущества JAX-WS 2.0:

  • Отделение технологии связывания данных от модели программирования Web-сервисов при помощи Java Architecture for XML Binding (JAXB) 2.0.
  • Поддержка SOAP 1.2, а также SOAP 1.1.
  • Поддержка WS-I Basic Profile 1.1 для улучшения совместимости Web-сервисов.
  • Использование вместо дескрипторов развертывания Web-сервисов аннотаций, определенных спецификациями JSR 181 (Web Services Metadata for the Java Platform) и JAX-WS. Поскольку все метаданные находятся в стандартизированных аннотациях, реализации Web-сервисов не зависят от производителей.
  • Поддержка модели асинхронного программирования на стороне клиента.
  • Упрощение создания обработчиков и предоставление механизма, позволяющего обработчикам работать совместно с клиентами сервисов и реализациями конечных точек сервисов.
  • Включение программных интерфейсов в платформы Java Platform, Extended Edition (Java EE) 5 и Java 2 Plaform, Standard Edition (J2SE) 6.

Программные интерфейсы JAX-WS 2.0 Сlient API

На рисунке 1 показаны взаимосвязи классов различных программных интерфейсов JAX-WS Сlient API. JAX-WS предоставляет набор программных интерфейсов клиента Web-сервиса для вызова операции на развернутой удаленно конечной точке сервиса. Эти программные интерфейсы можно использовать для динамического или статического, а также синхронного или асинхронного вызова операций.

Рисунок 1. Взаимосвязи программных интерфейсов JAX-WS Сlient API
Рисунок 1. Взаимосвязи программных интерфейсов JAX-WS Сlient API

Пример: создание клиента Dispatch

Оставшаяся часть статьи описывает создание клиента Dispatch из WSDL-документа и объясняет программный интерфейс. В примере используется следующий WSDL-документ:

Листинг 1. WSDL-определение
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="HelloWorldService"
   xmlns="http://schemas.xmlsoap.org/wsdl/"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
   xmlns:tns="http://www.example.com/services/HelloWorld"
   xmlns:types="http://www.example.com/schemas/HelloWorld"
   targetNamespace="http://www.example.com/services/HelloWorld">

   <types>
      <schema
		xmlns="http://www.w3.org/2001/XMLSchema"
	 	targetNamespace=”http://www.example.com/schemas/HelloWorld”>

		<element name=”hello”>
			<complexType>
				<sequence>
					<element name=”message” type=”string” />
				</sequence>
			</complexType>
		</element>

		<element name=”helloResponse”>
			<complexType>
				<sequence>
					<element name=”message” type=”string” />
				</sequence>
			</complexType>
		</element>
	</schema>
   </types>

   <message name="HelloRequest">
      <part name="firstName" element="types:hello"/>
   </message>

   <message name="HelloResponse">
      <part name="greeting" element=”types:helloResponse"/>
   </message>

   <portType name="HelloWorldSEI">
      <operation name="hello">
         <input message="tns:HelloRequest"/>
         <output message="tns:HelloResponse"/>
      </operation>
   </portType>
   
   <binding name="HelloSoap11Binding" type="tns:HelloWorldSEI">
      <soap:binding
		style="document" 
		transport="http://schemas.xmlsoap.org/soap/http"/>
      <operation name="hello">
         <soap:operation soapAction="hello"/>
         <input>
            <soap:body use="literal"/>
         </input>
         <output>
            <soap:body use="literal"/>
         </output>
      </operation>
   </binding>

   <service name="HelloService">
      <port binding="tns:HelloSoap11Binding" name="HelloPort">
         <soap:address
             location="http://localhost:8080/hello/services/HelloService"/>
      </port>
   </service>
</definitions>

Данный WSDL-документ описывает сервис HelloWorldService с единственным портом HelloPort. portType HelloWorldSEI определяет единственную операцию hello. Операция hello заключена в стиль document-literal, поэтому в ответ на передачу операции hello ожидается helloResponse.

Рассмотрим простой клиент Dispatch, который вызывает операцию hello. Сначала рассмотрим вызов целиком, а затем отдельные его части:

Листинг 2. Пример клиента JAX-WS javax.xml.ws.Dispatch
// Qnames для сервиса, как определено в wsdl.
QName serviceName =
  new Qname("http://www.example.com/services/HelloWorld", "HelloService");

//QName для порта, как определено в wsdl.
QName portName =
  new Qname("http://www.example.com/services/HelloWorld", "HelloPort");

//Адрес конечной точки
String  endpointAddress =
  "http://localhost:8080/hello/services/HelloService";

// Создание динамического экземпляра Service
Service service = Service.create(serviceName);

// Добавление порта в Service
service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, endpointAddress);

//Создание экземпляра dispatch
Dispatch<SOAPMessage> dispatch = 
   service.createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE);

// Использование Dispatch в качестве BindingProvider
BindingProvider bp = (BindingProvider) dispatch;

// Необязательная настройка RequestContext для отправки HTTP-заголовка SOAPAction
Map<String, Object> rc = bp.getRequestContext();
rc.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
rc.put(BindingProvider.SOAPACTION_URI_PROPERTY, "hello");

// Получение предварительно настроенного SAAJ MessageFactory
MessageFactory factory =
   ((SOAPBinding) bp.getBinding()).getMessageFactory();

// Создание запроса SOAPMessage Request
SOAPMessage request = factory.createMessage();

// Заголовок запроса
SOAPHeader header = request.getSOAPHeader();

// Тело запроса
SOAPBody body = request.getSOAPBody();

// Формирование полезной нагрузки soap:Body
QName payloadName =
   new QName("http://www.example.com/schemas/HelloWorld", "hello", "ns1");

SOAPBodyElement payload = body.addBodyElement(payloadName); 

SOAPElement message = payload.addChildElement("message");

message.addTextNode("Hello World!");

// Синхронный вызов конечной точки
SOAPMessage reply = null;

try {
	//Операция вызова конечной точки и чтение ответа
	reply = dispatch.invoke(request);
} catch (WebServiceException wse){
	wse.printStackTrace();
}

// Обработка ответа
body = reply.getSOAPBody();

QName responseName =
   new QName("http://www.example.com/schemas/HelloWorld", "helloResponse");

SOAPBodyElement bodyElement = body.getChildElements(responseName).next());
String message = bodyElement.getValue();

В приведенном выше примере можно выделить следующие этапы вызова операции в конечной точке использования программного интерфейса Dispatch:

  1. Создание и настройка динамического экземпляра Service.
  2. Создание клиента Dispatch.
  3. Настройка контекста запроса.
  4. Формирование запроса.
  5. Вызов операции.
  6. Обработка ответного сообщения.

Эти этапы описываются в следующих разделах.


Этап 1. Создание и настройка динамического экземпляра Service

Класс Service - это абстракция, представляющая WSDL-сервис. Экземпляр Service может быть динамическим сервисом (сервис создается на лету) или статическим экземпляром (класс, создаваемый инструментами JAX-WS, расширяет класс service). Основное внимание в статье уделяется динамическому сервису.

Для создания экземпляра Service J2SE-клиент может использовать метод Service.create(). Когда J2SE-клиент создает экземпляр Service, как показано в нашем примере, это динамический экземпляр Service, т.е. он настраивается динамически, а не статически, как в случае создания Service Class. Есть два способа создания экземпляра динамического сервиса:

  • create(QName serviceName) возвращает объект сервиса для сервиса с заданным именем. Ни один WSDL-документ не прикрепляется к сервису.

    Как показано в листинге 2, сначала определяется Service QName (в соответствии со спецификацией WSDL), которое затем используется для создания Service.

    Листинг 3. Создание динамического экземпляра Service
    //Qnames для сервиса
    QName serviceName =
      new Qname("http://www.example.com/services/HelloWorld", "HelloService");
    
    //Создание динамического экземпляра Service
    Service service = Service.create(serviceName);

    WSDL-сервис - это коллекция связанных портов, каждый из которых состоит из типа порта, привязанного к конкретному протоколу и доступного по адресу конкретной конечной точки. Как показано в листинге 2, мы определяем порт QName (в соответствии со спецификацией WSDL), а затем добавляем этот порт в Service.

    Листинг 4. Добавление порта в Service
    QName portName =
      new Qname("http://www.example.com/services/HelloWorld", "HelloPort");
    
    //Адрес конечной точки
    String  endpointAddress =
      "http://localhost:8080/hello/services/HelloService";
    
    // Добавление порта в Service
    service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, endpointAddress);
  • create(URL wsdlLocation, QName serviceName) возвращает объект сервиса для указанных WSDL-документа и имени сервиса, как показано в листинге 5:
    Листинг 5. Создание динамического сервиса с использованием WSDL
    //WSDL URL
    URL wsdlLocation = new URL("http://www.example.com/services/HelloWorld?wsdl");
    
    //Qname для сервиса
    QName serviceName =
      new Qname("http://www.example.com/services/HelloWorld", "HelloService");
    
    //Создание динамического экземпляра Service
    Service service = Service.create(wsdlLocation, serviceName);

Также мы могли бы использовать статический сервис. Использование статического сервиса возможно в случае, когда WSDL-файл скомпилирован при помощи инструментов JAX-WS для создания Java-артефактов. Однако был выбран динамический сервис, потому что:

  • мы не хотим создавать никаких артефактов;
  • во время написания клиента вызываемый сервис может быть неизвестен. Например, мы можем получить WSDL-документ от посредника, а затем использовать его для динамической настройки объекта сервиса;
  • мы используем отправку только для передачи сообщения, которое создается в другой системе.

Этап 2. Создание клиента Dispatch

Низкоуровневому программному интерфейсу Dispatch нужны клиенты для построения сообщений или полезной нагрузки сообщений на основе XML-технологии. Высокоуровневые программные интерфейсы JAX-WS скрывают подробности работы с XML и дают пользователям возможность работать с более привычными Java-объектами. Dispatch поддерживает два режима использования, определяемые следующими константами:

  • javax.xml.ws.Service.Mode.PAYLOAD
  • javax.xml.ws.Service.Mode.MESSAGE

В режиме PAYLOAD клиентские приложения работают с содержимым элемента <soap:Body> (полезная нагрузка сообщения), а не с сообщениями полностью. Если сервис использует SOAP-связывание, за предоставление SOAP-пакета отвечает среда исполнения JAX-WS.

Листинг 6. Создание экземпляра Dispatch в режиме PAYLOAD
//Создание экземпляра dispatch
Dispatch<SOAPMessage> dispatch = 
   service.createDispatch(portName, javax.xml.transform.Source.class,
Service.Mode.PAYLOAD);

В режиме MESSAGE клиентские приложения работают непосредственно с зависящими от протокола структурами сообщений. За предоставление SOAP-пакета и полезной нагрузки сообщения отвечает клиент. В нашем примере используется режим MESSAGE, как показано в листинге 7.

Листинг 7. Создание экземпляра dispatch в режиме MESSAGE
//Создание экземпляра dispatch
Dispatch<SOAPMessage> dispatch = 
   service.createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE);

Этап 3. Настройка контекста запроса

В программных интерфейсах JAX-WS Сlient API есть интерфейс BindingProvider, позволяющий работать с отдельными контекстами на этапах запроса и ответа при обмене сообщениями с конечной точкой. Контексты запроса и ответа имеют тип Map<String, Object> и извлекаются при помощи методов getRequestContext и getResponseContext интерфейса BindingProvider.

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

СвойствоНазначение
javax.xml.ws.service.endpoint.address Адрес конечной точки сервиса в виде зависящего от протокола URI. Схема URI должна соответствовать используемому связыванию протокола.
javax.xml.ws.security.auth.usernamejavax.xml.ws.security.auth.password Имя пользователя и пароль для HTTP-аутентификации.
javax.xml.ws.session.maintain Указывает, что клиент будет участвовать в HTTP-сеансе.
javax.xml.ws.soap.http.soapaction.usejavax.xml.ws.soap.http.soapaction.uri Определяет, используется ли HTTP-заголовок SOAPAction в SOAP-пакете поверх HTTP-запросов.
Листинг 8. Использование провайдера связывания для настройки RequestContext
//получение провайдера связывания
BindingProvider bp = (BindingProvider) dispatch;

// Настройка RequestContext (необязательный шаг)
Map<String, Object> rc = bp.getRequestContext();

//Запрос RequestContext для использования SOAPAction.
rc.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);

//Добавление SOAPAction в RequestContext
rc.put(BindingProvider.SOAPACTION_URI_PROPERTY, "hello");

Этап 4. Формирование запроса

В нашем примере используется Dispatch типа SOAPMessage, но отправки поддерживают также несколько других программных интерфейсов для формирования сообщения. Допустимыми типами отправок являются, например, javax.xml.transform.Source с DOMSource, субинтерфейсы SAXSource и StreamSource, объекты JAXB 2.0 и javax.activation.DataSource. В нашем примере продемонстрированы вызовы, использующие для формирования сообщения программный интерфейс SAAJ SOAPMessage, как показано в листинге 9:

Листинг 9. Создание SOAP-сообщения
//Создание запроса SOAPMessage Request
SOAPMessage request = factory.createMessage();

//Заголовок запроса
SOAPHeader header = request.getSOAPHeader();

//Тело запроса
SOAPBody body = request.getSOAPBody();

Как можно заметить, в данном случае payloadName - это QName элемента "hello" в XML Schema.

Листинг 10. WSDL-элемент, представляющий сигнатуру операции
 <schema
	xmlns="http://www.w3.org/2001/XMLSchema"
	targetNamespace="http://www.example.com/schemas/HelloWorld">

	<element name="hello">
		<complexType>
			<sequence>
				<element name="message" type="string" />
			</sequence>
		</complexType>
	</element>
</schema>

// Формирование полезной нагрузки soap:Body
QName payloadName =
   new QName("http://www.example.com/schemas/HelloWorld", "hello", "ns1");

SOAPBodyElement payload = body.addBodyElement(payloadName);
SOAPElement message = payload.addChildElement("message");
message.addTextNode("Hello World!");

Может возникнуть вопрос, почему мы решили построить наше сообщение таким способом. Наш простой WSDL использует SOAP-связывание в стиле document, как показано в листинге 11:

Листинг 11. SOAP-связывание в стиле document
<soap:binding
		style="document" 
		transport="http://schemas.xmlsoap.org/soap/http"/>

В этом стиле мы передаем точные XML-документы. В других стилях передаются сообщения, отформатированные иначе. В статье developerWorks Какой WSDL-стиль выбрать? (EN) описываются различные WSDL-стили и соответствующие им сообщения.


Этап 5. Вызов операции

Созданный запрос отправляется с использованием одного из методов Invoke экземпляра Dispatch. В нашем примере используется шаблон обмена сообщениями запрос-ответ, как показано в листинге 12.

Листинг 12. Экземпляр Dispatch, вызывающий операцию при помощи запроса
try {
	//Вызов операции конечной точки и чтение ответа
	reply = dispatch.invoke(request);
} catch (WebServiceException wse){
	wse.printStackTrace();
}

Если отправка запроса была неудачной, генерируется исключительная ситуация WebServiceException с указанием ее причины (например, HostNotFoundException). Если возникает проблема обработки запроса конечной точкой, генерируется исключительная ситуация SOAPFaultException.


Этап 6. Обработка ответного сообщения

Полученный из Invoke запрос подвергается окончательной обработке путем извлечения тела ответного SOAP-сообщения и его анализа в соответствии с WSDL-определением. В нашем примере ожидается получение XML-элемента helloResponse, как показано в листинге 13:

Листинг 13. Обработка ответа
<element name="helloResponse">
	<complexType>
		<sequence>
			<element name="message" type="string" />
		</sequence>
	</complexType>
</element>

// Обработка ответа
body = reply.getSOAPBody();

QName responseName =
   new QName("http://www.example.com/schemas/HelloWorld", "helloResponse");

SOAPBodyElement bodyElement = body.getChildElements(responseName).next());
String message = bodyElement.getValue();

Заключение

В этой статье вы познакомились с созданием клиента Dispatch, который используется для динамического вызова Web-сервиса. Вы также узнали о других программных интерфейсах JAX-WS Сlient API, которые используются для настройки контекста SOAP-сообщения, отправляемого на сервер. Реализация программного интерфейса Dispatch пакета WebSphere Application Server V6.1 Web Services Feature Pack поддерживает входные и выходные сообщения типов javax.xml.transform.Source, JAXB Object, javax.xml.soap.SoapMessage и java.lang.String. Клиентское приложение Web-сервисов может использовать программный интерфейс Dispatch для вызова одно- или двусторонних синхронных и асинхронных операций, реализованных конечной точкой Web-сервиса. Программный интерфейс Dispatch можно использовать для вызова Web-сервиса в некоторых других ситуациях:

  • Для обеспечения совместимости с Web-сервисами, разработанными в соответствии с устаревшей моделью программирования JAX-RPC или несовместимыми с WS-I.
  • Для вызова Web-сервиса с использованием xml/http-связывания и нетрадиционного SOAP-связывания.
  • Для вызова Web-сервиса с использованием связывания данных, отличного от JAXB.

Загрузка

ОписаниеИмяРазмер
Файл обмена проектаjaxwsDispatch.zip124 КБ
Файл обмена проектаjaxwsProxy_samples.zip158 КБ

Ресурсы

Научиться

Получить продукты и технологии

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=WebSphere, SOA и web-сервисы
ArticleID=783107
ArticleTitle=Программные интерфейсы JAX-WS Сlient API в Web Services Feature Pack for WebSphere Application Server V6.1: Часть 1. Создание клиента Dispatch
publish-date=12272011