Разработка приложений в Lotus Domino 7

Улучшение работы приложения фирмы ITSO Electronics с помощью Web-сервисов

Разбить на страницы
Показывать лекцию целиком

С появлением поддержки Web-сервисов Lotus Domino Designer 7 продолжает традицию поддержки новых стандартов для расширения возможностей его модели быстрой разработки приложений. Web-сервисы позволяют превратить приложения Lotus Domino в Web-сервисы, базирующиеся на сервере Lotus Domino, таким образом увеличивая возможность доступа к данным и обеспечивая обращение к приложениям через множество различных платформ. Благодаря тому, что все они построены на основе открытых стандартов, Web-сервисы – автономные, модульные приложения, способные работать друг с другом, без необходимости полагаться на соединения, запрограммированные пользователем. Так как Web-сервисы позволяют различным приложениям и информационным системам взаимодействовать друг с другом, серверные компоненты могут быть скомбинированы и рекомбинированы на лету, что позволяет компаниям быстро реагировать на постоянно меняющиеся потребности бизнеса и клиентов.

В этой лекции мы проанализируем, как улучшается приложение ITSO Electronics благодаря использованию Web-сервисов. Для этого рассмотрим следующие темы:

  • cервис-ориентированная архитектура: как Web-сервисы согласовываются с SOA (Server-Oriented Architecture);
  • Web-сервисы и язык описания Web-сервисов (Web Services Description Language, WDSL);
  • коммерческие предпосылки использования Web-сервисов;
  • элемент Web-сервиса: добавление простых и комплексных элементов Web-сервиса к приложению ITSO Electronics;
  • экспорт и импорт WSDL-документа;
  • обработка ошибок и исключений в Web-сервисах;
  • безопасность Web-сервисов;
  • использование Web-сервисов на языках программирования Java и LS2J/Lotus-Script.
  • 3.1 Сервис-ориентированная архитектура и Web-сервисы

    Сервис-ориентированная архитектура (SOA) является компонентной моделью, позволяющей взаимодействовать друг с другом различным функциональным модулям приложения, называемым сервисами, через строго определенный интерфейс (well-defined interface) и набор условий между этими сервисами. Интерфейс определен независимым способом, т. е. он должен быть независим от аппаратной платформы, операционной системы и языка программирования, на котором этот сервис реализован. Таким образом, становится возможным взаимодействие друг с другом сервисов, построенных на различных системах унифицированным и универсальным способом. Так как Web-сервисы характеризуются независимым от платформы подходом к разработке приложения, они являются неотъемлемым компонентом архитектуры SOA-приложения.

    Эта особенность, заключающаяся в независимом описании интерфейса, который не строго привязан к конкретной реализации, известна как слабая связь (loose coupling) между сервисами. Преимущество системы со слабой связью заключается в ее гибкости и способности сохранять работоспособность после эволюционных изменений в структуре и реализации функций каждого сервиса и всей программы в целом. Тем не менее, тесно связанные системы предполагают, что интерфейсы между различными компонентами приложения тесно взаимосвязаны, что делает их более непрочными, когда необходимо произвести изменения частей или всего приложения.

    Необходимость в системах со слабой связью растет из-за того, что с каждым днем возрастает потребность в более гибких бизнес-приложениях, которая, в свою очередь, основывается на том, что бизнес должен адаптироваться к изменчивости внешней среды, например к постоянно меняющимся принципам стратегии, устойчивости коммерческого положения, бизнес-целям, партнерству, состоянию промышленности, а также другим факторам, связанным с бизнесом, которые оказывают влияние на природу бизнеса. При желании вы можете обратиться к бизнесу, быстро реагирующему на изменения окружающей среды, т. е. к бизнесу по требованию (On Demand Business), который меняется в зависимости от того, как реализуются цели.

    Сервис-ориентированная архитектура не только является новшеством, но и представляет собой альтернативную модель более традиционным, жестко связанным (tightly coupled) объектно-ориентированным моделям, появившимся в последние десятилетия. Тогда как системы, базирующиеся на SOA, не исключают того факта, что отдельные сервисы сами могут быть построены по объектно-ориентированной схеме, схема всей системы сервис-ориентированна. Поскольку данное правило распространяется на объекты, находящиеся в пределах системы, SOA основана на объектах, но в целом не объектно-ориентированная. Различие заключается в самих интерфейсах. Классическим примером одной из самых первых SOA-систем является Common Object Request Broker Architecture (CORBA), оперирующая принципами, схожими с SOA.

    В настоящее время SOA использует преимущества языка XML (Extensible Markup Language). В результате описания интерфейсов на языках, основанных на XML, называемых языками описания Web-сервисов (Web Services Definition Language, WSDL)), Web-сервисы обрели более гибкие и динамичные системные интерфейсы по сравнению с разработанным ранее языком описания интерфейса (Interface Definition Language, IDL), использованным в CORBA.

    Помимо Web-сервисов существуют и другие способы реализации SOA, такие как CORBA и межплатформенные системы, ориентированные на информационный обмен, например IBM WebSphere $$\text{\textregistered}$$ MQ. Однако для того чтобы превратить ее в архитектурную модель, вам понадобится не просто описание сервиса. Необходимо описать то, как все приложение будет осуществлять последовательность операций между сервисами. Кроме того, необходимо найти подходящее для вашего бизнеса программное обеспечение. Следовательно, SOA должна быть связана с коммерческими бизнес-процессами подобно тому, как ITSO Electronics ориентируется на технические процессы и отображает взаимосвязь между технической и коммерческой стороной дела. Например, плата поставщику за услуги – бизнес-процесс, в то время как обновление базы данных ваших электронных компонентов с целью внесения новых компонентов – процесс технический. Таким образом, технологический процесс играет значительную роль в схеме SOA.

    3.2 Web-сервисы и WSDL

    Web-сервис представляет собой программную систему, предназначенную для поддержки взаимодействия компьютеров через сеть. Интерфейс Web-сервиса описан в формате, который компьютер способен обработать (конкретно WSDL). Другие системы взаимодействуют с Web-сервисом способами, предусмотренными его описанием, с использованием сообщений SOAP, которые обычно передаются посредством HTTP с XML-преобразованием вместе с другими стандартами, связанными с Web. Lotus Domino Designer 7 включает элемент дизайна "Web-сервис", а также встроенную поддержку языка описания Web-сервисов (WSDL). WSDL – это стандарт спецификации для описания сервисов, работающих по сети и основанных на XML. Он обеспечивает поставщиков услуг простым способом описания основного формата запросов к системам вне зависимости от того, откуда будут вызываться сервисы.

    Ограничения в реализации Web-сервисов в Lotus Domino 7 выражаются в следующем:

  • На "родном" уровне поддерживаются только те элементы, которые предоставляются провайдером.
  • Связь должна выполняться по простому протоколу доступа к объектам ( SOAP ) с помощью протоколов HTTP POST.
  • Элемент дизайна "Web-сервис" характеризуется следующими параметрами:

  • Скомпилированный Web-сервис, подобно Web-агенту, представляет собой отдельную автономную программу в базе данных Lotus Domino. Для того чтобы им воспользоваться, необходимо включить Web-сервис или отреплицировать его на сервер, к которому имеется Web-доступ. К нему можно получить доступ с помощью одной из приведенных ниже URL-команд Lotus Domino:
  • ?OpenWebService: используя протокол HTTP POST, запускает Web-сервис. Если использован протокол HTTP GET, то команда ?OpenWebService вернет некоторую информацию об этом сервисе.
  • ?WSDL: запрашивает у Web-сервиса его WSDL-документ.
  • Web-сервис можно протестировать во время HTTP-сессии в режиме предварительного просмотра Lotus Notes или Lotus Domino Designer.
  • Web-сервис имеет те же возможности по обеспечению безопасности, что и агент.
  • Вы можете импортировать существующий WSDL-документ, чтобы сгенерировать каркас Web-сервиса. Каркасный код соответствует описанию Web-сервиса. Затем вы добавляете исполнительный код.
  • В качестве альтернативы можно приступить к созданию Web-сервиса с нуля, написав собственный код на языке Java или LotusScript, чтобы создать описание Web-сервиса.
  • 3.2.1 Документ WSDL

    Документ WSDL определяет Web-сервис и включает в себя приведенные ниже элементы:

  • Сервис ( Service ).

    Web-сервис в целом. В документе WSDL сервис описывается элементом <definitions> в корне дерева. Дочерними являются элементы <types>, <message>, <port-Type>, <binding>, <service>. У элемента <service> есть атрибут "name", который используется для того, чтобы присвоить имя сервису.

  • Типы (

  • Сообщение ( Message ).

    Абстрактное описание данных, передаваемых или принимаемых сервисом. Допустимо любое количество сообщений. В документе WSDL каждое сообщение описывается элементом <message>. Каждый элемент <message> содержит один или более элементов <part>, необходимых для описания данных по имени и типу.

  • Тип порта ( PortType ).

    Абстрактный набор операций, поддерживаемых сервисом. В документе WSDL тип порта описывается элементом <portType>. Каждый элемент <portType> содержит один или более элементов <operation>.

  • Операция ( Operation ).

    Абстрактное описание действия, поддерживаемого сервисом. В документе WSDL операция описывается элементом <operation>. Каждый элемент <operation> содержит элементы <input> и <output>, определяющие связанные сообщения. Дополнительные элементы <fault> также могут быть определены.

  • Привязка ( "). Элемент <binding> содержит элементы <operation>, описывающие формат данных для каждой операции.

  • Порт ( Port ).

    Конечная точка, определенная в виде комбинации связывающего и сетевого адресов. В документе WSDL порт описывается элементом <port> под элементом <service>. У элемента <port> есть атрибут "binding", необходимый для присвоения имени связыванию, и атрибут "address location", необходимый для присвоения имени конечной точке сети, связанной с привязкой.

  • 3.2.2 Простой протокол доступа к объектам (SOAP)

    Элемент Web-сервисов Lotus Domino 7 обеспечивает средой для хостинга, основанной на простом протоколе доступа к объектам (SOAP) версии 1.1. SOAP определяет информацию, базирующуюся на XML и используемую для обмена структурированной и классифицированной информацией между равноправными участниками сети в децентрализованной, распределенной среде. Сообщение SOAP, по существу, представляет собой одностороннюю передачу от отправителя к получателю SOAP, однако предполагается, что сообщения SOAP комбинируются с помощью приложений для применения более сложных схем взаимодействия.

    Из положения консорциума Всемирной паутины (W3C):

    "SOAP is a lightweight protocol for exchanging structured information in a decentralized distributed environment. It is an XML based protocol that consists of three parts: an envelope that defines a framework for describing what is in a message and how to process it, a set of encoding rules for expressing instances of application-defined data types, and a convention for representing remote procedure calls and responsesС Web-сайта http://www.w3.org/Submission/2000/05/. ".

    ("SOAP представляет собой облегченный протокол, предназначенный для обмена структурированной информацией в децентрализованной и распределенной среде. Он основан на протоколе XML, состоящем из трех частей: оболочки, определяющей структуру для описания сообщения и процесса его обработки, набора правил кодирования, служащего для выражения экземпляров типов данных, определенных приложением, и правила, предназначенного для представления удаленных процедурных запросов и ответов".)

    3.2.3 Импортированный WSDL

    В Lotus Domino Designer 7 разработчик приложения может импортировать существующий файл WSDL в приложение и Domino Designer, затем сгенерировать классы на языке LotusScript или Java. Тем не менее, разработчики должны иметь в виду, что не все существующие WSDL-файлы могут быть интерпретированы Lotus Domino Designer 7. Некоторые файлы могут быть отклонены, в зависимости от используемых элементов XML.

    3.3 Коммерческие предпосылки использования Web-сервисов

    Начиная с Domino Release 5 появилась возможность написания приложений вне сервера Lotus Domino и получения доступа к данным Lotus Domino напрямую. Этого удалось достичь за счет использования привязок COM и CORBA к внутренним классам. Тем не менее, проблема проверки достоверности и согласованности данных, возможно, не была решена соответствующим образом с помощью внешних приложений. Web-сервисы предоставляют хороший компромисс между прямым доступом к данным и возможностью выполнения сетевых операций. Они предоставляют способ раскрытия функций приложений и данных в сети. Разработчики приложений на языке Java, Microsoft .NET, а также многих других могут получить доступ к данным Lotus Domino, просто используя Web-сервисы.

    Преимущества приложения, в котором внедрены Web-сервисы, лучше всего продемонстрировать на приложении ITSO Electronics, которое предоставляет клиентам текущую информацию о продуктах. Например, если приложение ITSO Electronics обещает пользователям доступ к информации о продуктах компании ITSO Electronics, ему необходимо разрешить доступ внешних приложений к базе данных покупателей вне зависимости от используемого приложения, будь то Java, J2EE или .NET. В связи с тем, что приложение покупателя отправляет запрос о получении информации Web-сервису, оно не должно зависеть от платформы и операционной системы. Web-сервис получает запрос о получении данных в виде сообщения XML. Следовательно, если пользователь введет запрос в форму приложения покупателя с целью получения информации о продукте компании ITSO Electronics, Web-сервис получит запрос в виде сообщения SOAP в формате XML и отправит ответ клиенту таким же образом. Используя расширенную поддержку, приложение ITSO Electronics может расширить свою функциональность в целях получения информации о цене продуктов от множества производителей. Используя Java, Web-сервис может отправлять запросы на получение данных на множество URL-адресов, запрашивая данные о цене, используя протокол XML. Все запросы отправляются в виде сообщений SOAP, и ответы приходят в таком же формате, в приложении ITSO Electronics. Пользователь при этом не знает ни о типе базы данных, из которой получает данные, ни об операционной системе, ни о платформе. Пользователи получают доступ, по-видимому, к неограниченному запасу данных, представленному с большой эффективностью.

    3.4 Добавление Web-сервисов к приложению ITSO Electronics

    Используя Web-сервисы и поддержку WSDL, вы можете быстро создавать или расширять код Java или LotusScript, открывая, таким образом доступ к тысячам приложений Lotus Domino из внешних систем, таких как Java 2 Platform, Enterprise Edition (J2EE) и приложениям Microsoft .NET. В этом разделе мы показываем, как улучшаются приложения ITSO Electronics путем внедрения Web-сервисов в среду разработки приложений Lotus Domino.

    Замечание Web-сервисы могут быть добавлены к любой базе данных Lotus Notes и Domino. Тем не менее, для достижения цели, поставленной в этой книге, все Web-сервисы добавлены к двум отдельным базам данных в приложении ITSO Electronics, которые называются webservices.nsf и wsconsumer.nsf.

    3.4.1 Коммерческие предпосылки добавления Web-сервисов к приложению ITSO Electronics

    Основным нашим требованием по внедрению Web-сервисов в приложение ITSO Electronics стала необходимость в просмотре покупателям и текущей информации о наших продуктах. Web-сервисы лучше всех справятся с подобной задачей. В будущем компания ITSO Electronics планирует использовать Web-сервисы для того, чтобы позволить покупателям получать доступ к информации о счетах, вне зависимости от используемой платформы, операционной системы или интерфейса.

    3.4.2 Пользовательские требования

    Основным пользователем Web-сервисов приложения ITSO Electronics в нашем примере будет клиент фирмы ITSO Electronics. Приложение необходимо для обеспечения доступа пользователя к текущей информации о продукте через программный механизм и пользовательский интерфейс, интуитивный и легкий в использовании.

    3.5 Создание простого Web-сервиса в Lotus Domino Designer 7

    Позвольте продемонстрировать вам, насколько легко создать Web-сервис с помощью IBM Lotus Domino Designer 7.

    Начнем с исключения ошибок, обработки особых ситуаций, регистрации и производительности. Сосредоточимся на функциональности ядра.

    Необходимо, чтобы приложение ITSO Electronics поддерживало и Java, и Lotus-Script.

    3.5.1 Создание нового Web-сервиса

    В этом разделе иллюстрируется создание нового Web-сервиса. В качестве примера используется приложение ITSO Electronics:

  • Откройте базу данных в Domino Designer. В нашем примере мы выбрали базу данных ITSO Web Services. Из списка дизайна выберите ).(рис 3.1) Окно свойств Web Service
  • Чтобы создать описание LotusScript, как на рис 3.2, вставьте или наберите код, приведенный в примере 3.1, в раздел Web-сервиса Declaration.
    (рис 3.1) Исходный код для простого Web-сервиса(рис 3.2) Код для простого Web-сервиса%INCLUDE "lsxsd.lss"
    Class ProductInfo
    Function getProductName(productNumber As String, Fault1 As WS_FAULT) As String
    Dim session As NotesSession
    Set session = New NotesSession
    Dim db As notesdatabase
    Dim view As notesview
    Dim doc As notesdocument
    Set db = session.GetDatabase("","itso/products.nsf")
    Set view = db.GetView("vaPNumber")
    Set doc = view.GetDocumentByKey(productNumber, True)
    If doc Is Nothing Then
    Call Fault1.setFault(True) ' необходимо для ошибочной активации
    Call Fault1.setFaultString("Product "  productnumber  " doesn't exist")
    Else
    getProductName = doc.ProductName(0)
    End If
    End Function
    End Class
  • Снова откройте окно свойств Web Service и в поле .(рис 3.3) Окно свойств Web Service: поле PortType class
  • Перейдите к закладке ).(рис 3.4) Окно свойств Web Service: закладка Advanced
  • Закройте окно свойств и сохраните Web-сервис.
  • 3.5.2 Просмотр Web-сервиса через браузер

    Для того чтобы протестировать новый Web-сервис ProductInfo, откройте браузер и введите следующий URL:

    http://servername/databasename.nsf/webservicename?openwebservice (http://имясервера/названиебазыданных.nsf/названиеWeb-сервиса?openwebservice)

    В нашем сценарии для приложения ITSO Electronics мы использовали приведенный ниже URL:

    http://domino7appdev.cam.itso.ibm.com/itso/webservices.nsf/ProductInfo?openwebservice

    Lotus Domino ответит на этот запрос именем порта Web-сервиса и названиями операций для этого порта, а также выведет ссылку на документ WSDL, как показано на рис 3.5.

    (рис 3.5) Web-сервис, открытый в Web-браузере

    3.5.3 Сгенерированный документ WSDL

    Приведенная ниже URL-команда Lotus Domino возвращает документ WSDL для Web-сервиса в ответ на HTTP GET, используя суффикс ?WSDL:

    http://servername/databasename.nsf/webservicename?WSDL (http://названиесервера/названиебазыданных.nsf/названиеWeb-сервиса?WSDL)

    Например, в нашем сценарии была использована следующая команда:

    http://domino7appdev.cam.itso.ibm.com/itso/webservices.nsf/ProductInfo?WSDL

    В примере 3.2 показан полученный в результате WSDL-документ.

    Для более подробного описания документа WSDL см. п. 3.2.1, "Документ WSDL".

    <?xml version="1.0" encoding="UTF-8"?>
    <wsdl:definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:
    apachesoap="http://xml.apache.org/xml-soap"
    xmlns:impl="urn:DefaultNamespace" xmlns:intf="urn:DefaultNamespace"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://
    schemas.xmlsoap.org/wsdl/"
    xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.
    w3.org/2001/XMLSchema"
    targetNamespace="urn:DefaultNamespace">
      <wsdl:message name="GETPRODUCTNAMERequest">
        <wsdl:part name="PRODUCTNUMBER" type="xsd:string"/>
      </wsdl:message>
      <wsdl:message name="GETPRODUCTNAMEResponse">
        <wsdl:part name="GETPRODUCTNAMEReturn" type="xsd:string"/>
      </wsdl:message>
      <wsdl:portType name="ProductInfo">
        <wsdl:operation name="GETPRODUCTNAME" parameterOrder="PRODUCTNUMBER">
          <wsdl:input message="impl:GETPRODUCTNAMERequest"
          name="GETPRODUCTNAMERequest"/>
          <wsdl:output message="impl:GETPRODUCTNAMEResponse"
          name="GETPRODUCTNAMEResponse"/>
        </wsdl:operation>
      </wsdl:portType>
      <wsdl:binding name="DominoSoapBinding" type="impl:ProductInfo">
        <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="GETPRODUCTNAME">
          <wsdlsoap:operation soapAction=""/>
          <wsdl:input name="GETPRODUCTNAMERequest">      
    
    <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    namespace="urn:DefaultNamespace"
    use="encoded"/>
          </wsdl:input>
          <wsdl:output name="GETPRODUCTNAMEResponse">
    
    <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    namespace="urn:DefaultNamespace"
    use="encoded"/>
          </wsdl:output>
        </wsdl:operation>
      </wsdl:binding>
      <wsdl:service name="ProductInfoService">
        <wsdl:port binding="impl:DominoSoapBinding" name="Domino">
          <wsdlsoap:address
    location="http://domino7appdev.cam.itso.ibm.com:80/itso/webservices.nsf/
    ProductInfo?OpenWebService"/>
        </wsdl:port>
      </wsdl:service>
    </wsdl:definitions>

    Полученный в результате генерации с суффиксом ?WSDL код сложен, однако это не важно, так как документы WSDL считываются компьютерами, а не пользователями. Например, Lotus Domino Designer может импортировать документ WSDL и создавать каркасный класс в LotusScript или Java. Обсуждением данной темы мы занимались в п. 3.2.3, "Импортированный WSDL".

    3.5.4 Тестирование простого Web-сервиса

    Существует множество приложений, которые позволяют тестировать и использовать Web-сервисы. Для достижения целей, поставленных в этой книге, мы будем использовать IBM Rational $$\text{\textregistered}$$ Application Developer. Чтобы начать тестирование Web-сервисов, используя Rational Application Developer, выполните приведенную ниже последовательность действий.

  • Запустите Rational Application Developer.
  • Выберите Run => Launch the Web Services Explorer (Выполнить $$\Rightarrow$$ Запустить обозреватель Web-сервисов).
  • Щелкните по иконке WSDL page (вторая справа, находится в верхней правой части основного окна).
  • Затем перейдите к панели .(рис 3.6) Выберите WSDL Main на панели Navigator
  • Перейдите к панели

  • Щелкните по кнопке .(рис 3.7) Панель WSDL Binding Details
  • В панели .(рис 3.8) Панель Invoke a WSDL Operation
  • Введем значение ).(рис 3.9) Панель Invoke a WSDL Operation Status
  • Чтобы увидеть, что на самом деле происходит "за кулисами", щелкните по кнопке .
    <?xml version="1.0" encoding="UTF-8" ?>
    - <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    - <SOAP-ENV:Body>
    - <ns0:GETPRODUCTNAME xmlns:ns0="urn:DefaultNamespace"
    SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
      <PRODUCTNUMBER xsi:type="xsd:string">45000</PRODUCTNUMBER>
      </ns0:GETPRODUCTNAME>
      </SOAP-ENV:Body>
      </SOAP-ENV:Envelope>
    soapenv:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    - <soapenv:Body>
    - <ns1:GETPRODUCTNAMEResponse xmlns:ns1="urn:DefaultNamespace"
    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
      <GETPRODUCTNAMEReturn xsi:type="xsd:string">Redbook Basic</GETPRODUCTNAMEReturn>
      </ns1:GETPRODUCTNAMEResponse>
      </soapenv:Body>
      </soapenv:Envelope>
    (рис 3.10) Исходный код, представленный в панели Status
  • Наконец, чтобы увидеть разницу в формате XML, вернитесь в Lotus Domino Designer и измените формат сообщения . Снова задействуйте Web-сервис GETPRODUCTNAME из Rational Application Developer. Результат будет таким же, как в примерах 3.5 и 3.6.
    (рис 3.5) Формат сообщения SOAP, установленный на Wrapped(рис 3.11) Контекст запроса SOAP, в котором использован формат сообщения SOAP Wrapped<?xml version="1.0" encoding="UTF-8" ?>
    - <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:q0="urn:DefaultNamespace" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    - <SOAP-ENV:Body>
    - <q0:GETPRODUCTNAME>
      <PRODUCTNUMBER>45000</PRODUCTNUMBER>
      </q0:GETPRODUCTNAME>
      </SOAP-ENV:Body>
      </SOAP-ENV:Envelope>
    - <soapenv:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    - <soapenv:Body>
    - <ns1:GETPRODUCTNAMEResponse xmlns:ns1="urn:DefaultNamespace">
      <GETPRODUCTNAMEReturn>Redbook Basic</GETPRODUCTNAMEReturn>
      </ns1:GETPRODUCTNAMEResponse>
      </soapenv:Body>
      </soapenv:Envelope>
  • Совет Браузеру Web-сервисов необходимо получать обновленный документ WSDL от Web-сервиса. Всякий раз, когда документ WSDL изменяется, ваши потребители (включая браузер Web-сервисов) должны использовать самую последнюю версию документа WSDL. В противном случае операции могут быть выполнены не так, как вы ожидаете.

    3.6 Создание сложного Web-сервиса в Lotus Domino Designer 7

    В предыдущем примере было продемонстрировано совместное использование примитивных видов данных, таких как массивы, числа или (как в нашем случае) строки. Требования к приложению ITSO Electronics заключаются в предоставлении покупателям прямого доступа к информации о продуктах. Web-сервисы же позволяют нам раскрыть эти данные. Покупатели и поставщики могут увидеть цену определенного продукта или получить список всех доступных продуктов.

    Для предоставления покупателям права доступа к информации о продуктах нам необходимо предоставить для совместного использования следующую информацию о продукте:

  • Название продукта ( Product name ).
  • Цена ( Price ).
  • Номер ( Number ).
  • Описание ( Description ).
  • В п. 3.5.1. В данном примере использован язык программирования Java.

    public class Product
    {
    private String name;
    private int number;
    private String description;
    private double price;
    public String getName(){ return name; }
    public int getNumber(){ return number; }
    public double getPrice(){ return price; }
    public String getDescription() { return description; }
    public void setName(String newName)
    {
    name = newName;
    }
    public void setNumber(int newNumber)
    {
    number = newNumber;
    }
    public void setDescription(String newDescription)
    {
    description = newDescription;
    }
    public void setPrice(double newPrice)
    {
    price = newPrice;
    }
    }

    В п. 3.5.1, "Создание нового Web-сервиса", мы создавали Web-сервис, используя примитивный тип данных. В этом примере мы предпримем те же действия для создания Web-сервиса для объекта Product, который позволит обеспечить партнеров подробной информацией о продуктах. В приведенных ниже действиях обобщается способ создания Web-сервиса.

  • Откройте базу данных ITSO Web Services в Domino Designer, затем Shared Code => Web Services (Общий код $$\Rightarrow$$ Web-сервисы). Щелкните по кнопке New Web Service (Создать Web-сервис).
  • В окне свойств Web-service, в поле Name, введите ProductService, таким образом вы присвоите имя своему Web-сервису. В качестве класса PortType используйте ProductService.
  • В панели Options переключитесь на Java.
  • Щелкните по кнопке New Class (Создать класс), после чего замените код предоставляемым по умолчанию кодом, представленным в примере 3.8. Этот код называется ProductService.java.
  • Снова щелкните по кнопке New Class и вставьте код из примера 3.7. Этот код называется Product.java.
  • Сохраните Web-сервис.
  • import lotus.domino.*;
    import lotus.domino.types.*;
    import java.util.*;
    public class ProductService
    {
    private Session session = WebServiceBase.getCurrentSession();
      public Object[] getAllProducts()
      {
      Product[] result = null;
      Database db = null;
      View view = null;
      Product product = null;
      ArrayList tempList = new ArrayList();
      try
      {
      db = getProductDb();
    view = db.getView("vaPNumber");
      Document doc2, doc = view.getFirstDocument();
      while(doc != null)
      {
    product = getProductFromDocument(doc);
    tempList.add(product);
    doc2 = doc;
    doc = view.getNextDocument(doc);
    doc2.recycle();
    }
    view.recycle();
    db.recycle();
      }catch(NotesException e){e.printStackTrace();}
    return tempList.toArray();
      }
    private Product getProductFromDocument(Document doc)
    {
    Product product = null;
    try
    {
    String name = doc.getItemValueString("ProductName");
    String description = doc.getItemValueString("ProductDescription");
    double price = doc.getItemValueDouble("ProductPrice");
    int productNumber = doc.getItemValueInteger("productNumber");
    product = new Product();
    product.setNumber(productNumber);
    product.setName(name);
    product.setPrice(price);
    product.setDescription(description);
    }
    catch(Exception e)
    {}
    return product;
    }
    private Database getProductDb()
    {
    Database db = null;
    try{
    db = session.getDatabase("","itso\\products.nsf");
    }catch(NotesException e){}
    return db;
    }
    public Product getProduct(double productNumber)
    {
    Product product = null;
      try
      {
        Database db = getProductDb();
    View view = db.getView("vaPNumber");
      Document doc = view.getDocumentByKey(new Double(productNumber), true);
        if(doc != null) {
          product = getProductFromDocument(doc);
          doc.recycle();
          doc = null;
        }
      view.recycle();
      db.recycle();
      }catch(NotesException e){}
      return product;
    }
    }

    Мы можем использовать новый Web-сервис, названный ProductService из Rational Application Developer, как показано на рис 3.12.

    (рис 3.12) Исполнение операции WSDL getProduct

    Пример 3.9 выводит контекст ответа SOAP, полученный от сервера Lotus Domino для определенного номера продукта, который мы использовали для активирования операции WSDL getProduct.

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    - <soapenv:Body>
    - <ns1:getProductResponse xmlns:ns1="urn:DefaultNamespace"
    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
      <getProductReturn href="#id0" />
      </ns1:getProductResponse>
    - <multiRef xmlns:ns2="urn:DefaultNamespace"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" id="id0" soapenc:
    root="0"
    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:
    type="ns2:Product">
    <description xsi:type="xsd:string">This is the basic Redbook offering.</description>
    <name xsi:type="xsd:string">Basic Redbook</name>
    <number xsi:type="xsd:int">20501</number>
    <price xsi:type=""xsd:double">102.0</price>
    </multiRef>
    </soapenv:Body>
    </soapenv:Envelope>

    У Web-сервиса ProductService, который мы только что создали, есть и другая операция, отправляющая набор объектов продуктов в виде массива, которая называется getAll-Products. Пример 3.10 наглядно иллюстрирует этот процесс. Его сообщения SOAP имеют формат RPC/encoded.

    - <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    - <soapenv:Body>
    - <ns1:getAllProductsResponse xmlns:ns1="urn:DefaultNamespace"
    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    - <getAllProductsReturn xmlns:soapenc="http://schemas.xmlsoap.org/soap/
    encoding/"
    soapenc:arrayType="xsd:anyType[9]" xsi:type="soapenc:Array">
      <item href="#id0" />
      <item href="#id1" />
      <item href="#id2" />
      <item href="#id3" />
      <item href="#id4" />
      <item href="#id5" />
      <item href="#id6" />
      <item href="#id7" />
      <item href="#id8" />
      </getAllProductsReturn>
      </ns1:getAllProductsResponse>
    - <multiRef xmlns:ns2="urn:DefaultNamespace"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" id="id1" soapenc:
    root="0"
    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:
    type="ns2:Product">
      <description xsi:type="xsd:string">Redpaper mid-tier line available at
    newsagents and
    department stores.</description>
      <name xsi:type="xsd:string">Redpaper Deluxe</name>
      <number xsi:type="xsd:int">10002</number>
      <price xsi:type="xsd:double">2299.0</price>
      </multiRef>
    - <multiRef xmlns:ns3="urn:DefaultNamespace"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" id="id8" soapenc:
    root="0"
    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:
    type="ns3:Product">
      <description xsi:type="xsd:string">The best Redbook money can buy.</
    description>
      <name xsi:type="xsd:string">Redbook Plus</name>
      <number xsi:type="xsd:int">45500</number>
      <price xsi:type="xsd:double">50000.0</price>
      </multiRef>
    и так далее.......
    - <multiRef xmlns:ns10="urn:DefaultNamespace"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" id="id6" soapenc:
    root="0"
    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:
    type="ns10:Product">
      <description xsi:type="xsd:string">The ultimate Redbook experience.</
    description>
      <name xsi:type="xsd:string">Redbook Supreme</name>
      <number xsi:type="xsd:int">20564</number>
      <price xsi:type="xsd:double">1000.0</price>
      </multiRef>
      </soapenv:Body>
      </soapenv:Envelope>

    3.7 Экспортирование документа WSDL

    Документы WSDL экспортируют для того, чтобы предоставить покупателю информацию о том, как использовать созданные Web-сервисы. Во многих случаях инструменты, с помощью которых осуществляется создание клиентов Web-сервисов, могут автоматически генерировать код из документа WSDL.

    Для того чтобы экспортировать документ WSDL, выполните следующие действия:

  • Откройте базу данных ITSO Web Services в Domino Designer и выберите Shared Code => Web Services (Общий код $$\Rightarrow$$ Web-сервисы).
  • Выберите ProductService и щелкните по кнопке Export WSDL (Экспортировать документ WSDL).
  • После этого будет сгенерирован файл .
  • (рис 3.13) Экспортирование документа WSDL

    3.8 Импортирование документа WSDL

    Если вы импортируете документ WSDL, описательный класс генерируется на основе содержания документа WSDL. Общедоступные прототипы методов, функций и подстановок в классе соответствуют операциям Web-сервиса, определенным для первого элемента <port> первого элемента <service> в документе WSDL. Другие классы или типы ссылаются на прототипы методов, которые, возможно, также будут сгенерированы на основании содержимого документа WSDL вместе с общедоступными элементами данных. Если вы измените прототип интерфейса, соответствующий документ WSDL также изменится, когда Web-сервис будет сохранен. Вы можете отслеживать подобные изменения с помощью свойства "Warn if the WSDL interface is modified" (Предупреждать, если интерфейс WSDL был изменен).

    Бизнес-партнеры компании ITSO Electronics, а, возможно, и покупатели, в свою очередь, могут обеспечивать компанию документом WSDL, который она может использовать для создания Web-сервисов. Вы можете импортировать существующий документ WSDL, чтобы сгенерировать каркас Web-сервиса. Каркасный код соответствует описанию Web-сервиса. Затем вам необходимо добавить код реализации.

    Для того чтобы импортировать документ WSDL, выполните следующее:

  • Откройте базу данных ITSO Web Services в Domino Designer, затем выберите Shared Code => Web Services.
  • Щелкните по кнопке ).(рис 3.14) Импортирование документа WSDL
  • В результате импортирования документа WSDL будет сгенерирован каркасный код, который в нашем сценарии сгенерирован на языке LotusScript, как показано в примере 3.11. Затем мы открыли окно свойств Web Service, поставили галочку рядом с опцией ).
    (рис 3.11) Импортирование документа WSDL: окно свойств Web Service(рис 3.15) Каркасный код, сгенерированный после импортирования документа WSDL%INCLUDE "lsxsd.lss"
    Class ArrayOfProduct_Holder As INOUT_HOLDER
    Public Value() As Product
    End Class
    Class Product
    Public description As XSD_STRING
    Public name As XSD_STRING
    Public number As Long
    Public price As Double
    Sub NEW
    End Sub
    End Class
    Class ProductService
    Sub NEW
    End Sub
    Function getAllProducts() As ArrayOfProduct_Holder
    End Function
    Function getProduct(productNumber As Double) As Product
    End Function
    End Class
  • 3.9 Работа с исключениями и ошибками в Web-сервисах

    Операции также могут возвращать ошибки посредством подкласса ошибок, который соответствует некоторому сообщению <wsdl:fault>, выбранному для определенной операции в документе WSDL, или посредством прямого использования базового класса WS_FAULT (LotusScript), или класса lotus.domino.types.Fault, или класса java.lang.Exception(Java).

    Замечание Любые ошибки в методе описания сервиса на языке LotusScript (т. е. любой основной класс или подкласс WS_FAULT ) должны фигурировать в конце списка параметров метода.

    Ошибки для метода описания сервиса на языке Java возникают в стандартных предложениях Java.

    Для получения дополнительной информации о том, как работать с ошибками, используя язык LotusScript см. п. 3.12, "Использование Web-сервисов с помощью LS2J".

    3.10 Безопасность в Web-сервисах

    Угрозы безопасности Web-сервисов, определенных в приложении ITSO Electronics, подразумевают угрозу всей системе, на которой базируется Web-сервис, приложению и инфраструктуре сети в целом. Для обеспечения защиты Web-сервисов необходим целый спектр механизмов защиты, основанных на языке XML, так как только благодаря им становится возможным решение проблем, касающихся аутентификации, ролевого контроля доступа к базам данных, реализации принципов обеспечения безопасности, а также безопасности уровня сообщений, которая выполняет роль посредника.

    В настоящий момент не существует общепринятых спецификаций безопасности Web-сервисов. Поэтому разработчики могут либо создавать службы, которые не используют подобных возможностей, либо разрабатывать специальные узкопрофильные программы, которые предположительно смогут решать проблемы функциональной совместимости.

    Для применения Web-сервисов могут потребоваться механизмы защиты "точка-точка" или сквозные механизмы защиты, или оба механизма в зависимости от степени угрозы или риска. Традиционные механизмы безопасности, построенные на основе соединений "точка-точка", возможно, не смогут справиться с потребностями в сквозной защите Web-служб. Тем не менее, безопасность – это баланс между оцененным риском и затратами на противодействие. В зависимости от допускаемого риска использования защита, обеспечиваемая соединением "точка-точка", работающая на уровне переноса данных, позволяет обеспечить достаточными мерами безопасности.

    В архитектуре приложения ITSO Electronics существует три фундаментальных принципа, относящихся к безопасности: ресурсы, которые должны быть защищены; механизмы, благодаря которым обеспечивается эта защита (т. е. политика защиты); и политики, которые представляют собой обрабатываемые компьютерами документы, которые, описывают ограничения на этих ресурсах. Для продолжения дискуссии о безопасности применения Web-сервисов обратитесь к руководству Web Service Architecture, которое доступно по следующему адресу в Интернете: http://www.w3.org/TR/2004/NOTE-ws-arch-20040211

    Web-сервис Lotus Domino 7 обладает теми же возможностями защиты, что и агент. Уровень защиты Web-сервиса устанавливается в закладке Security (Безопасность) окна свойств Web service. В приведенном ниже списке описываются параметры, доступные в закладке Security.

  • Run as web user (Запускать от лица Web-пользователя): код Java или LotusScript запускается с реальным именем пользователя, который запустил Web-сервис.
  • Run on behalf of (Запускать от лица): код Java или LotusScript запускается на полномочиях определенного пользователя. Тем не менее, подписчик Web-сервиса должен обладать неограниченными правами на сервер или правом запускать Web-сервисы от лица любого пользователя.
  • Set runtime security level (Установить уровень защиты выполнения) (один из перечисленных ниже):
  • Do not allow restricted operations (Не разрешать выполнение операций с ограниченным доступом);
  • Allow restricted operations (Разрешать выполнение операций с ограниченным доступом);
  • Allow restricted operations with full administration rights (Разрешать выполнение операций с ограниченным доступом с полными правами администрирования).
  • Default access for this web service (Доступ по умолчанию к этому Web-сервису):
  • All readers and above (Все читатели и выше). Вы можете выбрать или снять этот параметр.
  • Enumerated (Перечисленные). Если вы убрали галочку рядом с параметром All readers and above, то с помощью этого параметра вы можете выбрать тех, кому вы хотите предоставить доступ по умолчанию.
  • Allow Public Access users to use this web service (Разрешить пользователям открытого доступа применять этот Web-сервис). Если выбран этот параметр, пользователи, обладающие открытым доступом к документам в базе данных, получают доступ по умолчанию.
  • 3.11 Использование Web-сервисов с помощью Java

    На момент написания этой книги Lotus Domino 7.0 обеспечивал, хотя и не в полном объеме, использование Web-сервисов. Тем не менее, вспомогательным бизнес-требованием, предъявляемым к приложению ITSO Electronics, является предоставление доступа к ценовым данным, располагающимся за границами Lotus Domino, что, в свою очередь, диктует необходимость использования Web-сервисов в этом приложении. В нашем сценарии компания ITSO Electronics решила применить программный продукт с открытым исходным кодом

    Для того чтобы проиллюстрировать использование Web-сервисов, в нашем сценарии мы создали отдельную базу данных в приложении ITSO Electronics, которую назвали WS Consumer. В этой базе данных содержится агент, который будет использовать сложный Web-сервис, созданный нами ранее.

    Замечание Web-сервисы могут быть добавлены к любой базе данных Lotus Notes и Domino. Но для достижения целей, поставленных в этой книге, все Web-сервисы добавлены к отдельным базам данных в приложении ITSO Electronics, которые называются webservices.nsf и wsconsumer.nsf.

    Приведенная ниже последовательность действий наглядно иллюстрирует создание агента, использующего Web-сервис.

  • Загрузите самую последнюю версию Apache SOAP по следующей ссылке: http://ws.apache.org/soap/
  • Извлеките загруженный файл во временную директорию, в нашем сценарии в качестве такой папки мы использовали папку c:\soap.
  • Экспортируйте сложный Web-сервис ProductService (находящийся в базе данных Web Services) в документ WSDL. В экспортированном документе WSDL содержится вся информация, необходимая для использования Web-сервиса.
  • Откройте документ WSDL в текстовом редакторе. Документ WSDL содержит информацию, описывающую сложный тип данных, возвращаемых этим Web-сервисом, как видно из примера 3.12. В нашем случае этот сложный тип данных называется Product. Сложный элемент Type показывает свойства объекта Product, к которым относятся описание, название, номер и цена.
    <wsdl:types>
      <schema targetNamespace="urn:DefaultNamespace" xmlns="http://www.w3.org/2001/
    XMLSchema"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
    <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
    <complexType name="Product">
      <sequence>
        <element name="description" nillable="true" type="xsd:string"/>
        <element name="name" nillable="true" type="xsd:string"/>
        <element name="number" type="xsd:int"/>
        <element name="price" type="xsd:double"/>
      </sequence>
    </complexType>
    <complexType name="ArrayOfProduct">
      <complexContent>
        <restriction base="soapenc:Array">
         <attribute ref="soapenc:arrayType" wsdl:arrayType="impl:Product[]"/>
        </restriction>
       </complexContent>
      </complexType>
     </schema>
    </wsdl:types>
  • Откройте новую базу данных WS Consumer в Domino Designer, выберите Shared Code => Agents (Общий код $$\Rightarrow$$ Агенты), после чего щелкните по кнопке New agent (Создать агент).
  • В поле .(рис 3.16) Окно свойств ConsumerWS Agent
  • Закройте окно свойств Agent, затем выберите язык кода Java.
  • Нам необходимо создать класс JavaBean, представляющий сложный тип данных Product, определенный в документе WSDL. Для облегчения этой операции мы воспользуемся возможностью импортирования WSDL для автоматической генерации класса JavaBean. После этого нам необходимо выбрать Shared Code => Web Service (Общий код $$\Rightarrow$$ Web-сервис) и щелкнуть по кнопке New Web Service (Создать Web-сервис).
  • Закройте окно свойств Web Service и убедитесь в том, что язык описания Web-сервиса установлен на Java. Щелкните по кнопке Import WSDL (Импортировать WSDL), затем выберите созданный ранее документ WSDL. В результате импортирования этого документа будут автоматически созданы классы JavaBeansTM.
  • Выделите и скопируйте код Java для Product.java.
  • Вернитесь к агенту и щелкните по кнопке New Class (Создать класс). Затем замените класс Untitled.java скопированным кодом Product.java, так же, как это сделано в примере 3.13.
  • Сохраните агент ConsumeWS и убедитесь в том, что он был успешно скомпилирован.

    Щелкните по кнопке ). Перейдите к нужной директории библиотеки SOAP LIB, в нашем случае эта директория находилась по следующему пути: c:\soap\soap-2_3_1\lib. В качестве типа файла выберите Archive (Архивный), щелкните по кнопке Add/Replace File(s) (Добавить/Заменить файлы), далее нажмите ОК.

    (рис 3.17) Окно Organize Java Agent Files
  • Вам необходимо код JavaAgent.java по умолчанию заменить своим собственным, чтобы приступить к использованию Web-сервиса, который в нашем сценарии представлен в примере 3.14. Убедитесь в том, что в классе JavaAgent.java есть переменные URL и soapAction. Эти переменные должны указывать на расположение вашего приложения.
  • Сохраните агент ConsumeWS.
  • Вернитесь к новому Web-сервису и закройте его без сохранения.
  • Откройте клиент Lotus Notes и выберите базу данных WS Consumer. Перейдите к .(рис 3.18) Окно Java, в котором отображен результат работы Web-сервисаЕсли окно не открылось, выберите File => Tools => Show Java Debug Console (Файл $$\Rightarrow$$ Сервис $$\Rightarrow$$ Показать консоль отладки Java) для получения дополнительной информации.
  • public class Product {
    private java.lang.String description;
    private java.lang.String name;
    private int number;
    private double price;
    public Product() {
    }
    public java.lang.String getDescription() {
    return description;
    }
    public void setDescription(java.lang.String description)
    this.description = description;
    }
    public java.lang.String getName() {
    return name;
    }
    public void setName(java.lang.String name) {
    this.name = name;
    }
    public int getNumber() {
    return number;
    }
    public void setNumber(int number) {
    this.number = number;
    }
    public double getPrice() {
    return price;
    }
    public void setPrice(double price) {
    this.price = price;
    }
    private java.lang.Object __equalsCalc = null;
    public synchronized boolean equals(java.lang.Object obj) {
    if (!(obj instanceof Product)) return false;
    Product other = (Product) obj;
    if (obj == null) return false;
    if (this == obj) return true;
    if (__equalsCalc != null) {
    return (__equalsCalc == obj);
    }
    __equalsCalc = obj;
    boolean _equals;
    _equals = true 
    ((this.description==null  other.getDescription()==null) |
     (this.description!=null 
      this.description.equals(other.getDescription()))) 
    ((this.name==null  other.getName()==null) ||
     (this.name!=null 
      this.name.equals(other.getName()))) 
    this.number == other.getNumber() 
    this.price == other.getPrice();
    __equalsCalc = null;
    return _equals;
    }
    private boolean __hashCodeCalc = false;
    public synchronized int hashCode() {
    if (__hashCodeCalc) {
    return 0;
    }
    __hashCodeCalc = true;
    int _hashCode = 1;
    if (getDescription() != null) {
    _hashCode += getDescription().hashCode();
    }
    if (getName() != null) {
    _hashCode += getName().hashCode();
    }
    _hashCode += getNumber();
    _hashCode += new Double(getPrice()).hashCode();
    __hashCodeCalc = false;
    return _hashCode;
    }
    }
    import lotus.domino.*;
    import java.io.*;
    import java.util.*;
    import java.net.*;
    import org.w3c.dom.*;
    import org.apache.soap.util.xml.*;
    import org.apache.soap.*;
    import org.apache.soap.encoding.*;
    import org.apache.soap.encoding.soapenc.*;
    import org.apache.soap.rpc.*;
    import javax.swing.*;
    public class JavaAgent extends AgentBase
    {
        public void NotesMain()
        {
            try
            {
                Session session = getSession();
                AgentContext agentContext = session.getAgentContext();
    
    URL url = new URL("http://domino7appdev.cam.itso.ibm.com/itso/webservices.nsf/
    ProductService?WSDL");
    
    String soapAction ="http://domino7appdev.cam.itso.ibm.com/itso/webservices.nsf/
    ProductService?WSDL";
                Call call = new Call();
                BeanSerializer beanSerializer = new BeanSerializer();
                SOAPMappingRegistry smRegistry = new SOAPMappingRegistry();
                smRegistry.mapTypes(Constants.NS_URI_SOAP_ENC, new QName(
                        "urn:DefaultNamespace", "Product"), Product.class,
    beanSerializer,
                        beanSerializer);
                String targetNamespace = "urn:DefaultNamespace";
                call.setSOAPMappingRegistry(smRegistry);
                call.setTargetObjectURI(targetNamespace);
                call.setMethodName("getAllProducts");
                call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
                Response resp = null;
                try
                {
                    resp = call.invoke(url, soapAction);
                } catch (SOAPException e)
                {
                    e.printStackTrace();
    
    System.err.println("SOAP Exception code: " + e.getFaultCode() + " message: " + e.ge
                    return;
                }
                if (!resp.generatedFault())
                {
                    Parameter ret = resp.getReturnValue();
                    Product[] products = (Product[]) ret.getValue();
                    buildGUI(products);
                }
      else
                {
                    Fault fault = resp.getFault();
    
    System.err.println("SOAP Fault, " + fault.getFaultCode() + " " + fault.
    getFaultS
                }
            } catch (Exception e)
            {
                e.printStackTrace();
            }
        }
        private void buildGUI(Product[] products)
        {
              StringBuffer sb = new StringBuffer();
              String newLine = "<br>";
              for(int i = 0; i < products.length; i++)
              {
              sb.append(newLine + newLine);
    
    sb.append(products[i].getName() + " (" + products[i].getNumber() + ")" +
    newLine);
              sb.append( " * " + products[i].getDescription());
              sb.append(newLine + " * " + products[i].getPrice());
    }
              JFrame frame = new JFrame("Web service content");
              frame.getContentPane().add(new JScrollPane(new JLabel("<html>" + sb.
    toString() + "</html>")));
              frame.pack();
              frame.setVisible(true);
    }
    }

    3.12 Использование Web-сервисов с помощью LS2J

    В этом разделе мы расскажем о следующем:

  • как использовать Web-сервис с помощью LotusScript;
  • как с помощью LS2J обращаться к коду Java из агента LotusScript;
  • как работать с исключениями или ошибками, возвращаемыми назад от Web-сервисов;
  • об аутентификации и Web-сервисах.
  • 3.12.1 Несколько слов о LS2J

    LS2J представляет собой интерфейс, позволяющий переводить данные из типов данных Java в типы данных LotusScript и позволяет LotusScript выполнять методы объектов Java. Благодаря LS2J LotusScript получает способность создавать объекты Java так, будто они были родными для среды LotusScript.

    В этом сценарии мы добавили агент LotusScript к базе данных WS Consumer. Агент использует код Java из библиотеки скриптов, для того чтобы использовать Web-сервис.

    Web-сервис, который мы используем, способен выполнять одно из двух действий:

  • возвращать имя текущего пользователя;
  • возвращать объект WS_FAULT, для того чтобы проиллюстрировать, как Web-сервисы способны отправлять коды ошибок обратно к клиенту.
  • 3.12.2 Создание Web-сервиса

    Перечисленные ниже этапы показывают, как создать Web-сервис с помощью LS2J. В этом разделе описывается создание Web-сервиса, а в последующих речь пойдет о создании библиотеки скриптов Java и о том, как она используется в нашем агенте LotusScript через LS2J. Выполните приведенную ниже последовательность действий.

  • Откройте базу данных Web Services в Domino Designer.
  • Щелкните по кнопке New Web Service.
  • Убедитесь, что установлен язык кода LotusScript.
  • Перейдите к разделу Declarations и перепечатайте код, представленный в примере 3.15.
    Dim session As NotesSession
    Class UserInfo
        Function getUserName ( Fault1 As WS_FAULT)
            Set session = New NotesSession
            Dim doc As NotesDocument
            Set doc = session.DocumentContext
            If Cint(Rnd() * 10) > 5 Then
               getUserName = doc.remote_user(0)
            Else
               Call Fault1.setFault(True) ' необходимо для ошибочной активации
               Call Fault1.setFaultString("SUCCESS, We send a FAULT on purpose")
            End If
        End Function
    End Class
  • Откройте окно свойств Web-сервиса и в поле .
  • Сохраните и закройте Web-сервис.
  • (рис 3.19) Окно свойств LS2J Web Service UserInfo

    3.12.3 Создание библиотеки скриптов, необходимой для использования Web-сервиса с помощью Java

    Теперь нам необходимо создать библиотеку скриптов, содержащую класс Java, который будет использовать Web-сервис и сделает его доступным нашему агенту LotusScript через LS2J. Для того чтобы настроить класс Java, необходимо выполнить следующую последовательность действий:

  • Откройте базу данных WS Consumer в Domino Designer.
  • В навигационной панели выберите Shared Code (Общий код) и щелкните по кнопке New Java Library (Новая библиотека Java).
  • В открывшемся окне щелкните по кнопке ). Если у вас отсутствует файл Apache soap.jar, необходимо вернуться к п. 3.11, "Использование Web-сервисов с помощью Java" для получения дополнительной информации о том, как загрузить Apache SOAP.
  • Сохраните библиотеку скриптов под именем ConsumeWSLibrary.
  • Замените код для библиотеки по умолчанию кодом, приведенным в примере 3.16.
  • Важно Приведенные ниже строчки из примера 3.16 должны быть скорректированы и соответствовать URL вашей базы данных:
    URL url = new URL("http://domino7appdev.cam.itso.ibm.com/itso/
    webservices.nsf/ProductService?WSDL");
    String soapAction ="http://domino7appdev.cam.itso.ibm.com/itso/
    webservices.nsf/ProductService?WSDL";
    (рис 3.16) Импортирование архива Java, который будет использован с LS2J(рис 3.20) Код Java, необходимый для использования Web-сервисов средой LS2Jimport java.io.*;
    import java.util.*;
    import java.net.*;
    import org.w3c.dom.*;
    import org.apache.soap.util.xml.*;
    import org.apache.soap.*;
    import org.apache.soap.encoding.*;
    import org.apache.soap.encoding.soapenc.*;
    import org.apache.soap.rpc.*;
    import org.apache.soap.transport.http.SOAPHTTPConnection;
    public class WSConsumer
    {
        public String getValue(String userName, String password)
        {
            try
            {
    URL url = new URL("http://domino7appdev.cam.itso.ibm.com/itso/webservices.nsf/
    UserInfo?WSDL");
    
    String soapAction ="http://domino7appdev.cam.itso.ibm.com/itso/webservices.nsf/
    UserInfo?WSDL";
                Call call = new Call();
                SOAPHTTPConnection hc = new SOAPHTTPConnection();
      hc.setUserName(userName);
         hc.setPassword(password);
                call.setSOAPTransport(hc);
                SOAPMappingRegistry smRegistry = new SOAPMappingRegistry();
                String targetNamespace = "urn:DefaultNamespace";
                call.setSOAPMappingRegistry(smRegistry);
                call.setTargetObjectURI(targetNamespace);
                call.setMethodName("getUserName");
                call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
                Response resp = null;
                try
                {
                    resp = call.invoke(url, soapAction);
                } catch (SOAPException e)
                {
                    e.printStackTrace();
    return ("SOAP Exception code: " + e.getFaultCode() + " message: " +
    e.getMessage());
                }
                if (!resp.generatedFault())
                {
                    Parameter ret = resp.getReturnValue();
    return ret.getValue() + "";
                }
      else
                {
                    Fault fault = resp.getFault();
                    return ("SOAP Fault, " + fault.getFaultCode() + " " + fault.
    getFaultString());
                }
            } catch (Exception e)
            {
                e.printStackTrace();
            }
            return null;
        }
    }

    3.12.4 Создание агента, используя язык LotusScript

    Наконец нам необходимо создать агент LotusScript и использовать только что созданную библиотеку через LS2J.

  • В панели Navigation выберите Shared Code => Agents.
  • Щелкните по кнопке New Agent. В окне свойств нового агента, в поле Name, введите LotusScriptConsumeWS, а в выпадающем списке Target раздела Runtime выберите None. Закройте окно свойств.
  • Измените язык на LotusScript.
  • В Declarations замените код по умолчанию кодом, приведенным в примере 3.17.
  • В Initialize замените код по умолчанию кодом из примера 3.18.Замечание Скорректируйте строчку value = myObject.getValue("The UserName", "The Password"), введя правильное имя пользователя и пароль.
    Option Public
    Use "ConsumeWSLibrary"
    Uselsx "*javacon"
    Sub Initialize
    Dim mySession As JavaSession
    Dim myClass As JavaClass
    Dim myObject As JavaObject
    Set mySession = New JavaSession ()
    Set myClass = mySession.GetClass("WSConsumer")
    Set myObject = myClass.CreateObject
    Dim value As String
    value = myObject.getValue("The UserName", "The Password")
    Msgbox value
    End Sub
  • Сохраните и закройте агент.
  • В клиенте Lotus Notes запустите только что созданный агент. Если вы увидите сообщение, которое представлено на рис 3.21, то оно, скорее всего, вызвано тем, что вы не обеспечили код точным именем пользователя и паролем.
  • (рис 3.21) Сообщение об ошибке, возникшей при использовании Web-сервиса с помощью LS2J

    Если агент смог использовать ваш Web-сервис, вы увидите сообщение, представленное на рис 3.22.

    (рис 3.22) Web-сервис был успешно использован с помощью LS2J

    3.12.5 Аутентификация и Web-сервисы

    В Lotus Notes и Domino 7 Web-сервис обладает теми же возможностями защиты, что и агент. В примере 3.19 мы использовали базовую аутентификацию HTTP, для того чтобы защитить наш Web-сервис. Apache SOAP позволяет нам отправлять имена пользователей и пароли в виде SOAP-запросов, добавляя экземпляр класса SOAPHTTPConnection к объекту Call.

    Call call = new Call();
    SOAPHTTPConnection hc = new SOAPHTTPConnection();
    hc.setUserName(userName);
    hc.setPassword(password);
    call.setSOAPTransport(hc);

    3.13 Какой стиль WSDL мне следует использовать?

    В документе WSDL содержится XML-код, который описывает Web-сервис. Привязка WSDL описывает то, как сервис связан с протоколом обмена сообщениями. Привязка WSDL SOAP может быть осуществлена либо при помощи вызова удаленных процедур (RPC), либо при помощи документной привязки. Привязка SOAP также может употребляться как в кодированном виде, так и в литеральном виде. Таким образом, у разработчика приложений Lotus Domino есть четыре типа/моделей использования на выбор:

  • вызов удаленных процедур/кодированный (RPC/encoded);
  • вызов удаленных процедур/литеральный (RPC/literal);
  • документальный/литеральный (Document/literal);
  • заключенный в оболочку (Wrapped).
  • Терминология "RPC против документального" может сбивать с толку, так как эти термины подразумевают, что тип RPC следует использовать для программируемых моделей RPC и что документальный тип нужно использовать для документальных программируемых моделей или для программируемых моделей обмена сообщениями. Тем не менее, в данном случае все эти заблуждения бессмысленны, так как тип не имеет ничего общего с программируемыми моделями. Типы только диктуют то, как переводить привязку WSDL в сообщение SOAP. Подобно этому, типы кодированный и литеральный имеют значение только в привязке WSDL-к-SOAP.

    Страницы:

    С появлением поддержки Web-сервисов Lotus Domino Designer 7 продолжает традицию поддержки новых стандартов для расширения возможностей его модели быстрой разработки приложений. Web-сервисы позволяют превратить приложения Lotus Domino в Web-сервисы, базирующиеся на сервере Lotus Domino, таким образом увеличивая возможность доступа к данным и обеспечивая обращение к приложениям через множество различных платформ. Благодаря тому, что все они построены на основе открытых стандартов, Web-сервисы – автономные, модульные приложения, способные работать друг с другом, без необходимости полагаться на соединения, запрограммированные пользователем. Так как Web-сервисы позволяют различным приложениям и информационным системам взаимодействовать друг с другом, серверные компоненты могут быть скомбинированы и рекомбинированы на лету, что позволяет компаниям быстро реагировать на постоянно меняющиеся потребности бизнеса и клиентов.

    В этой лекции мы проанализируем, как улучшается приложение ITSO Electronics благодаря использованию Web-сервисов. Для этого рассмотрим следующие темы:

  • cервис-ориентированная архитектура: как Web-сервисы согласовываются с SOA (Server-Oriented Architecture);
  • Web-сервисы и язык описания Web-сервисов (Web Services Description Language, WDSL);
  • коммерческие предпосылки использования Web-сервисов;
  • элемент Web-сервиса: добавление простых и комплексных элементов Web-сервиса к приложению ITSO Electronics;
  • экспорт и импорт WSDL-документа;
  • обработка ошибок и исключений в Web-сервисах;
  • безопасность Web-сервисов;
  • использование Web-сервисов на языках программирования Java и LS2J/Lotus-Script.
  • 3.1 Сервис-ориентированная архитектура и Web-сервисы

    Сервис-ориентированная архитектура (SOA) является компонентной моделью, позволяющей взаимодействовать друг с другом различным функциональным модулям приложения, называемым сервисами, через строго определенный интерфейс (well-defined interface) и набор условий между этими сервисами. Интерфейс определен независимым способом, т. е. он должен быть независим от аппаратной платформы, операционной системы и языка программирования, на котором этот сервис реализован. Таким образом, становится возможным взаимодействие друг с другом сервисов, построенных на различных системах унифицированным и универсальным способом. Так как Web-сервисы характеризуются независимым от платформы подходом к разработке приложения, они являются неотъемлемым компонентом архитектуры SOA-приложения.

    Эта особенность, заключающаяся в независимом описании интерфейса, который не строго привязан к конкретной реализации, известна как слабая связь (loose coupling) между сервисами. Преимущество системы со слабой связью заключается в ее гибкости и способности сохранять работоспособность после эволюционных изменений в структуре и реализации функций каждого сервиса и всей программы в целом. Тем не менее, тесно связанные системы предполагают, что интерфейсы между различными компонентами приложения тесно взаимосвязаны, что делает их более непрочными, когда необходимо произвести изменения частей или всего приложения.

    Необходимость в системах со слабой связью растет из-за того, что с каждым днем возрастает потребность в более гибких бизнес-приложениях, которая, в свою очередь, основывается на том, что бизнес должен адаптироваться к изменчивости внешней среды, например к постоянно меняющимся принципам стратегии, устойчивости коммерческого положения, бизнес-целям, партнерству, состоянию промышленности, а также другим факторам, связанным с бизнесом, которые оказывают влияние на природу бизнеса. При желании вы можете обратиться к бизнесу, быстро реагирующему на изменения окружающей среды, т. е. к бизнесу по требованию (On Demand Business), который меняется в зависимости от того, как реализуются цели.

    Сервис-ориентированная архитектура не только является новшеством, но и представляет собой альтернативную модель более традиционным, жестко связанным (tightly coupled) объектно-ориентированным моделям, появившимся в последние десятилетия. Тогда как системы, базирующиеся на SOA, не исключают того факта, что отдельные сервисы сами могут быть построены по объектно-ориентированной схеме, схема всей системы сервис-ориентированна. Поскольку данное правило распространяется на объекты, находящиеся в пределах системы, SOA основана на объектах, но в целом не объектно-ориентированная. Различие заключается в самих интерфейсах. Классическим примером одной из самых первых SOA-систем является Common Object Request Broker Architecture (CORBA), оперирующая принципами, схожими с SOA.

    В настоящее время SOA использует преимущества языка XML (Extensible Markup Language). В результате описания интерфейсов на языках, основанных на XML, называемых языками описания Web-сервисов (Web Services Definition Language, WSDL)), Web-сервисы обрели более гибкие и динамичные системные интерфейсы по сравнению с разработанным ранее языком описания интерфейса (Interface Definition Language, IDL), использованным в CORBA.

    Помимо Web-сервисов существуют и другие способы реализации SOA, такие как CORBA и межплатформенные системы, ориентированные на информационный обмен, например IBM WebSphere $$\text{\textregistered}$$ MQ. Однако для того чтобы превратить ее в архитектурную модель, вам понадобится не просто описание сервиса. Необходимо описать то, как все приложение будет осуществлять последовательность операций между сервисами. Кроме того, необходимо найти подходящее для вашего бизнеса программное обеспечение. Следовательно, SOA должна быть связана с коммерческими бизнес-процессами подобно тому, как ITSO Electronics ориентируется на технические процессы и отображает взаимосвязь между технической и коммерческой стороной дела. Например, плата поставщику за услуги – бизнес-процесс, в то время как обновление базы данных ваших электронных компонентов с целью внесения новых компонентов – процесс технический. Таким образом, технологический процесс играет значительную роль в схеме SOA.

    3.2 Web-сервисы и WSDL

    Web-сервис представляет собой программную систему, предназначенную для поддержки взаимодействия компьютеров через сеть. Интерфейс Web-сервиса описан в формате, который компьютер способен обработать (конкретно WSDL). Другие системы взаимодействуют с Web-сервисом способами, предусмотренными его описанием, с использованием сообщений SOAP, которые обычно передаются посредством HTTP с XML-преобразованием вместе с другими стандартами, связанными с Web. Lotus Domino Designer 7 включает элемент дизайна "Web-сервис", а также встроенную поддержку языка описания Web-сервисов (WSDL). WSDL – это стандарт спецификации для описания сервисов, работающих по сети и основанных на XML. Он обеспечивает поставщиков услуг простым способом описания основного формата запросов к системам вне зависимости от того, откуда будут вызываться сервисы.

    Ограничения в реализации Web-сервисов в Lotus Domino 7 выражаются в следующем:

  • На "родном" уровне поддерживаются только те элементы, которые предоставляются провайдером.
  • Связь должна выполняться по простому протоколу доступа к объектам ( SOAP ) с помощью протоколов HTTP POST.
  • Элемент дизайна "Web-сервис" характеризуется следующими параметрами:

  • Скомпилированный Web-сервис, подобно Web-агенту, представляет собой отдельную автономную программу в базе данных Lotus Domino. Для того чтобы им воспользоваться, необходимо включить Web-сервис или отреплицировать его на сервер, к которому имеется Web-доступ. К нему можно получить доступ с помощью одной из приведенных ниже URL-команд Lotus Domino:
  • ?OpenWebService: используя протокол HTTP POST, запускает Web-сервис. Если использован протокол HTTP GET, то команда ?OpenWebService вернет некоторую информацию об этом сервисе.
  • ?WSDL: запрашивает у Web-сервиса его WSDL-документ.
  • Web-сервис можно протестировать во время HTTP-сессии в режиме предварительного просмотра Lotus Notes или Lotus Domino Designer.
  • Web-сервис имеет те же возможности по обеспечению безопасности, что и агент.
  • Вы можете импортировать существующий WSDL-документ, чтобы сгенерировать каркас Web-сервиса. Каркасный код соответствует описанию Web-сервиса. Затем вы добавляете исполнительный код.
  • В качестве альтернативы можно приступить к созданию Web-сервиса с нуля, написав собственный код на языке Java или LotusScript, чтобы создать описание Web-сервиса.
  • 3.2.1 Документ WSDL

    Документ WSDL определяет Web-сервис и включает в себя приведенные ниже элементы:

  • Сервис ( Service ).

    Web-сервис в целом. В документе WSDL сервис описывается элементом <definitions> в корне дерева. Дочерними являются элементы <types>, <message>, <port-Type>, <binding>, <service>. У элемента <service> есть атрибут "name", который используется для того, чтобы присвоить имя сервису.

  • Типы (

  • Сообщение ( Message ).

    Абстрактное описание данных, передаваемых или принимаемых сервисом. Допустимо любое количество сообщений. В документе WSDL каждое сообщение описывается элементом <message>. Каждый элемент <message> содержит один или более элементов <part>, необходимых для описания данных по имени и типу.

  • Тип порта ( PortType ).

    Абстрактный набор операций, поддерживаемых сервисом. В документе WSDL тип порта описывается элементом <portType>. Каждый элемент <portType> содержит один или более элементов <operation>.

  • Операция ( Operation ).

    Абстрактное описание действия, поддерживаемого сервисом. В документе WSDL операция описывается элементом <operation>. Каждый элемент <operation> содержит элементы <input> и <output>, определяющие связанные сообщения. Дополнительные элементы <fault> также могут быть определены.

  • Привязка ( "). Элемент <binding> содержит элементы <operation>, описывающие формат данных для каждой операции.

  • Порт ( Port ).

    Конечная точка, определенная в виде комбинации связывающего и сетевого адресов. В документе WSDL порт описывается элементом <port> под элементом <service>. У элемента <port> есть атрибут "binding", необходимый для присвоения имени связыванию, и атрибут "address location", необходимый для присвоения имени конечной точке сети, связанной с привязкой.

  • 3.2.2 Простой протокол доступа к объектам (SOAP)

    Элемент Web-сервисов Lotus Domino 7 обеспечивает средой для хостинга, основанной на простом протоколе доступа к объектам (SOAP) версии 1.1. SOAP определяет информацию, базирующуюся на XML и используемую для обмена структурированной и классифицированной информацией между равноправными участниками сети в децентрализованной, распределенной среде. Сообщение SOAP, по существу, представляет собой одностороннюю передачу от отправителя к получателю SOAP, однако предполагается, что сообщения SOAP комбинируются с помощью приложений для применения более сложных схем взаимодействия.

    Из положения консорциума Всемирной паутины (W3C):

    "SOAP is a lightweight protocol for exchanging structured information in a decentralized distributed environment. It is an XML based protocol that consists of three parts: an envelope that defines a framework for describing what is in a message and how to process it, a set of encoding rules for expressing instances of application-defined data types, and a convention for representing remote procedure calls and responsesС Web-сайта http://www.w3.org/Submission/2000/05/. ".

    ("SOAP представляет собой облегченный протокол, предназначенный для обмена структурированной информацией в децентрализованной и распределенной среде. Он основан на протоколе XML, состоящем из трех частей: оболочки, определяющей структуру для описания сообщения и процесса его обработки, набора правил кодирования, служащего для выражения экземпляров типов данных, определенных приложением, и правила, предназначенного для представления удаленных процедурных запросов и ответов".)

    3.2.3 Импортированный WSDL

    В Lotus Domino Designer 7 разработчик приложения может импортировать существующий файл WSDL в приложение и Domino Designer, затем сгенерировать классы на языке LotusScript или Java. Тем не менее, разработчики должны иметь в виду, что не все существующие WSDL-файлы могут быть интерпретированы Lotus Domino Designer 7. Некоторые файлы могут быть отклонены, в зависимости от используемых элементов XML.

    3.3 Коммерческие предпосылки использования Web-сервисов

    Начиная с Domino Release 5 появилась возможность написания приложений вне сервера Lotus Domino и получения доступа к данным Lotus Domino напрямую. Этого удалось достичь за счет использования привязок COM и CORBA к внутренним классам. Тем не менее, проблема проверки достоверности и согласованности данных, возможно, не была решена соответствующим образом с помощью внешних приложений. Web-сервисы предоставляют хороший компромисс между прямым доступом к данным и возможностью выполнения сетевых операций. Они предоставляют способ раскрытия функций приложений и данных в сети. Разработчики приложений на языке Java, Microsoft .NET, а также многих других могут получить доступ к данным Lotus Domino, просто используя Web-сервисы.

    Преимущества приложения, в котором внедрены Web-сервисы, лучше всего продемонстрировать на приложении ITSO Electronics, которое предоставляет клиентам текущую информацию о продуктах. Например, если приложение ITSO Electronics обещает пользователям доступ к информации о продуктах компании ITSO Electronics, ему необходимо разрешить доступ внешних приложений к базе данных покупателей вне зависимости от используемого приложения, будь то Java, J2EE или .NET. В связи с тем, что приложение покупателя отправляет запрос о получении информации Web-сервису, оно не должно зависеть от платформы и операционной системы. Web-сервис получает запрос о получении данных в виде сообщения XML. Следовательно, если пользователь введет запрос в форму приложения покупателя с целью получения информации о продукте компании ITSO Electronics, Web-сервис получит запрос в виде сообщения SOAP в формате XML и отправит ответ клиенту таким же образом. Используя расширенную поддержку, приложение ITSO Electronics может расширить свою функциональность в целях получения информации о цене продуктов от множества производителей. Используя Java, Web-сервис может отправлять запросы на получение данных на множество URL-адресов, запрашивая данные о цене, используя протокол XML. Все запросы отправляются в виде сообщений SOAP, и ответы приходят в таком же формате, в приложении ITSO Electronics. Пользователь при этом не знает ни о типе базы данных, из которой получает данные, ни об операционной системе, ни о платформе. Пользователи получают доступ, по-видимому, к неограниченному запасу данных, представленному с большой эффективностью.

    3.4 Добавление Web-сервисов к приложению ITSO Electronics

    Используя Web-сервисы и поддержку WSDL, вы можете быстро создавать или расширять код Java или LotusScript, открывая, таким образом доступ к тысячам приложений Lotus Domino из внешних систем, таких как Java 2 Platform, Enterprise Edition (J2EE) и приложениям Microsoft .NET. В этом разделе мы показываем, как улучшаются приложения ITSO Electronics путем внедрения Web-сервисов в среду разработки приложений Lotus Domino.

    Замечание Web-сервисы могут быть добавлены к любой базе данных Lotus Notes и Domino. Тем не менее, для достижения цели, поставленной в этой книге, все Web-сервисы добавлены к двум отдельным базам данных в приложении ITSO Electronics, которые называются webservices.nsf и wsconsumer.nsf.

    3.4.1 Коммерческие предпосылки добавления Web-сервисов к приложению ITSO Electronics

    Основным нашим требованием по внедрению Web-сервисов в приложение ITSO Electronics стала необходимость в просмотре покупателям и текущей информации о наших продуктах. Web-сервисы лучше всех справятся с подобной задачей. В будущем компания ITSO Electronics планирует использовать Web-сервисы для того, чтобы позволить покупателям получать доступ к информации о счетах, вне зависимости от используемой платформы, операционной системы или интерфейса.

    3.4.2 Пользовательские требования

    Основным пользователем Web-сервисов приложения ITSO Electronics в нашем примере будет клиент фирмы ITSO Electronics. Приложение необходимо для обеспечения доступа пользователя к текущей информации о продукте через программный механизм и пользовательский интерфейс, интуитивный и легкий в использовании.

    3.5 Создание простого Web-сервиса в Lotus Domino Designer 7

    Позвольте продемонстрировать вам, насколько легко создать Web-сервис с помощью IBM Lotus Domino Designer 7.

    Начнем с исключения ошибок, обработки особых ситуаций, регистрации и производительности. Сосредоточимся на функциональности ядра.

    Необходимо, чтобы приложение ITSO Electronics поддерживало и Java, и Lotus-Script.

    3.5.1 Создание нового Web-сервиса

    В этом разделе иллюстрируется создание нового Web-сервиса. В качестве примера используется приложение ITSO Electronics:

  • Откройте базу данных в Domino Designer. В нашем примере мы выбрали базу данных ITSO Web Services. Из списка дизайна выберите ).(рис 3.1) Окно свойств Web Service
  • Чтобы создать описание LotusScript, как на рис 3.2, вставьте или наберите код, приведенный в примере 3.1, в раздел Web-сервиса Declaration.
    (рис 3.1) Исходный код для простого Web-сервиса(рис 3.2) Код для простого Web-сервиса%INCLUDE "lsxsd.lss"
    Class ProductInfo
    Function getProductName(productNumber As String, Fault1 As WS_FAULT) As String
    Dim session As NotesSession
    Set session = New NotesSession
    Dim db As notesdatabase
    Dim view As notesview
    Dim doc As notesdocument
    Set db = session.GetDatabase("","itso/products.nsf")
    Set view = db.GetView("vaPNumber")
    Set doc = view.GetDocumentByKey(productNumber, True)
    If doc Is Nothing Then
    Call Fault1.setFault(True) ' необходимо для ошибочной активации
    Call Fault1.setFaultString("Product "  productnumber  " doesn't exist")
    Else
    getProductName = doc.ProductName(0)
    End If
    End Function
    End Class
  • Снова откройте окно свойств Web Service и в поле .(рис 3.3) Окно свойств Web Service: поле PortType class
  • Перейдите к закладке ).(рис 3.4) Окно свойств Web Service: закладка Advanced
  • Закройте окно свойств и сохраните Web-сервис.
  • 3.5.2 Просмотр Web-сервиса через браузер

    Для того чтобы протестировать новый Web-сервис ProductInfo, откройте браузер и введите следующий URL:

    http://servername/databasename.nsf/webservicename?openwebservice (http://имясервера/названиебазыданных.nsf/названиеWeb-сервиса?openwebservice)

    В нашем сценарии для приложения ITSO Electronics мы использовали приведенный ниже URL:

    http://domino7appdev.cam.itso.ibm.com/itso/webservices.nsf/ProductInfo?openwebservice

    Lotus Domino ответит на этот запрос именем порта Web-сервиса и названиями операций для этого порта, а также выведет ссылку на документ WSDL, как показано на рис 3.5.

    (рис 3.5) Web-сервис, открытый в Web-браузере

    3.5.3 Сгенерированный документ WSDL

    Приведенная ниже URL-команда Lotus Domino возвращает документ WSDL для Web-сервиса в ответ на HTTP GET, используя суффикс ?WSDL:

    http://servername/databasename.nsf/webservicename?WSDL (http://названиесервера/названиебазыданных.nsf/названиеWeb-сервиса?WSDL)

    Например, в нашем сценарии была использована следующая команда:

    http://domino7appdev.cam.itso.ibm.com/itso/webservices.nsf/ProductInfo?WSDL

    В примере 3.2 показан полученный в результате WSDL-документ.

    Для более подробного описания документа WSDL см. п. 3.2.1, "Документ WSDL".

    <?xml version="1.0" encoding="UTF-8"?>
    <wsdl:definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:
    apachesoap="http://xml.apache.org/xml-soap"
    xmlns:impl="urn:DefaultNamespace" xmlns:intf="urn:DefaultNamespace"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://
    schemas.xmlsoap.org/wsdl/"
    xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.
    w3.org/2001/XMLSchema"
    targetNamespace="urn:DefaultNamespace">
      <wsdl:message name="GETPRODUCTNAMERequest">
        <wsdl:part name="PRODUCTNUMBER" type="xsd:string"/>
      </wsdl:message>
      <wsdl:message name="GETPRODUCTNAMEResponse">
        <wsdl:part name="GETPRODUCTNAMEReturn" type="xsd:string"/>
      </wsdl:message>
      <wsdl:portType name="ProductInfo">
        <wsdl:operation name="GETPRODUCTNAME" parameterOrder="PRODUCTNUMBER">
          <wsdl:input message="impl:GETPRODUCTNAMERequest"
          name="GETPRODUCTNAMERequest"/>
          <wsdl:output message="impl:GETPRODUCTNAMEResponse"
          name="GETPRODUCTNAMEResponse"/>
        </wsdl:operation>
      </wsdl:portType>
      <wsdl:binding name="DominoSoapBinding" type="impl:ProductInfo">
        <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="GETPRODUCTNAME">
          <wsdlsoap:operation soapAction=""/>
          <wsdl:input name="GETPRODUCTNAMERequest">      
    
    <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    namespace="urn:DefaultNamespace"
    use="encoded"/>
          </wsdl:input>
          <wsdl:output name="GETPRODUCTNAMEResponse">
    
    <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    namespace="urn:DefaultNamespace"
    use="encoded"/>
          </wsdl:output>
        </wsdl:operation>
      </wsdl:binding>
      <wsdl:service name="ProductInfoService">
        <wsdl:port binding="impl:DominoSoapBinding" name="Domino">
          <wsdlsoap:address
    location="http://domino7appdev.cam.itso.ibm.com:80/itso/webservices.nsf/
    ProductInfo?OpenWebService"/>
        </wsdl:port>
      </wsdl:service>
    </wsdl:definitions>

    Полученный в результате генерации с суффиксом ?WSDL код сложен, однако это не важно, так как документы WSDL считываются компьютерами, а не пользователями. Например, Lotus Domino Designer может импортировать документ WSDL и создавать каркасный класс в LotusScript или Java. Обсуждением данной темы мы занимались в п. 3.2.3, "Импортированный WSDL".

    3.5.4 Тестирование простого Web-сервиса

    Существует множество приложений, которые позволяют тестировать и использовать Web-сервисы. Для достижения целей, поставленных в этой книге, мы будем использовать IBM Rational $$\text{\textregistered}$$ Application Developer. Чтобы начать тестирование Web-сервисов, используя Rational Application Developer, выполните приведенную ниже последовательность действий.

  • Запустите Rational Application Developer.
  • Выберите Run => Launch the Web Services Explorer (Выполнить $$\Rightarrow$$ Запустить обозреватель Web-сервисов).
  • Щелкните по иконке WSDL page (вторая справа, находится в верхней правой части основного окна).
  • Затем перейдите к панели .(рис 3.6) Выберите WSDL Main на панели Navigator
  • Перейдите к панели

  • Щелкните по кнопке .(рис 3.7) Панель WSDL Binding Details
  • В панели .(рис 3.8) Панель Invoke a WSDL Operation
  • Введем значение ).(рис 3.9) Панель Invoke a WSDL Operation Status
  • Чтобы увидеть, что на самом деле происходит "за кулисами", щелкните по кнопке .
    <?xml version="1.0" encoding="UTF-8" ?>
    - <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    - <SOAP-ENV:Body>
    - <ns0:GETPRODUCTNAME xmlns:ns0="urn:DefaultNamespace"
    SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
      <PRODUCTNUMBER xsi:type="xsd:string">45000</PRODUCTNUMBER>
      </ns0:GETPRODUCTNAME>
      </SOAP-ENV:Body>
      </SOAP-ENV:Envelope>
    soapenv:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    - <soapenv:Body>
    - <ns1:GETPRODUCTNAMEResponse xmlns:ns1="urn:DefaultNamespace"
    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
      <GETPRODUCTNAMEReturn xsi:type="xsd:string">Redbook Basic</GETPRODUCTNAMEReturn>
      </ns1:GETPRODUCTNAMEResponse>
      </soapenv:Body>
      </soapenv:Envelope>
    (рис 3.10) Исходный код, представленный в панели Status
  • Наконец, чтобы увидеть разницу в формате XML, вернитесь в Lotus Domino Designer и измените формат сообщения . Снова задействуйте Web-сервис GETPRODUCTNAME из Rational Application Developer. Результат будет таким же, как в примерах 3.5 и 3.6.
    (рис 3.5) Формат сообщения SOAP, установленный на Wrapped(рис 3.11) Контекст запроса SOAP, в котором использован формат сообщения SOAP Wrapped<?xml version="1.0" encoding="UTF-8" ?>
    - <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:q0="urn:DefaultNamespace" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    - <SOAP-ENV:Body>
    - <q0:GETPRODUCTNAME>
      <PRODUCTNUMBER>45000</PRODUCTNUMBER>
      </q0:GETPRODUCTNAME>
      </SOAP-ENV:Body>
      </SOAP-ENV:Envelope>
    - <soapenv:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    - <soapenv:Body>
    - <ns1:GETPRODUCTNAMEResponse xmlns:ns1="urn:DefaultNamespace">
      <GETPRODUCTNAMEReturn>Redbook Basic</GETPRODUCTNAMEReturn>
      </ns1:GETPRODUCTNAMEResponse>
      </soapenv:Body>
      </soapenv:Envelope>
  • Совет Браузеру Web-сервисов необходимо получать обновленный документ WSDL от Web-сервиса. Всякий раз, когда документ WSDL изменяется, ваши потребители (включая браузер Web-сервисов) должны использовать самую последнюю версию документа WSDL. В противном случае операции могут быть выполнены не так, как вы ожидаете.

    3.6 Создание сложного Web-сервиса в Lotus Domino Designer 7

    В предыдущем примере было продемонстрировано совместное использование примитивных видов данных, таких как массивы, числа или (как в нашем случае) строки. Требования к приложению ITSO Electronics заключаются в предоставлении покупателям прямого доступа к информации о продуктах. Web-сервисы же позволяют нам раскрыть эти данные. Покупатели и поставщики могут увидеть цену определенного продукта или получить список всех доступных продуктов.

    Для предоставления покупателям права доступа к информации о продуктах нам необходимо предоставить для совместного использования следующую информацию о продукте:

  • Название продукта ( Product name ).
  • Цена ( Price ).
  • Номер ( Number ).
  • Описание ( Description ).
  • В п. 3.5.1. В данном примере использован язык программирования Java.

    public class Product
    {
    private String name;
    private int number;
    private String description;
    private double price;
    public String getName(){ return name; }
    public int getNumber(){ return number; }
    public double getPrice(){ return price; }
    public String getDescription() { return description; }
    public void setName(String newName)
    {
    name = newName;
    }
    public void setNumber(int newNumber)
    {
    number = newNumber;
    }
    public void setDescription(String newDescription)
    {
    description = newDescription;
    }
    public void setPrice(double newPrice)
    {
    price = newPrice;
    }
    }

    В п. 3.5.1, "Создание нового Web-сервиса", мы создавали Web-сервис, используя примитивный тип данных. В этом примере мы предпримем те же действия для создания Web-сервиса для объекта Product, который позволит обеспечить партнеров подробной информацией о продуктах. В приведенных ниже действиях обобщается способ создания Web-сервиса.

  • Откройте базу данных ITSO Web Services в Domino Designer, затем Shared Code => Web Services (Общий код $$\Rightarrow$$ Web-сервисы). Щелкните по кнопке New Web Service (Создать Web-сервис).
  • В окне свойств Web-service, в поле Name, введите ProductService, таким образом вы присвоите имя своему Web-сервису. В качестве класса PortType используйте ProductService.
  • В панели Options переключитесь на Java.
  • Щелкните по кнопке New Class (Создать класс), после чего замените код предоставляемым по умолчанию кодом, представленным в примере 3.8. Этот код называется ProductService.java.
  • Снова щелкните по кнопке New Class и вставьте код из примера 3.7. Этот код называется Product.java.
  • Сохраните Web-сервис.
  • import lotus.domino.*;
    import lotus.domino.types.*;
    import java.util.*;
    public class ProductService
    {
    private Session session = WebServiceBase.getCurrentSession();
      public Object[] getAllProducts()
      {
      Product[] result = null;
      Database db = null;
      View view = null;
      Product product = null;
      ArrayList tempList = new ArrayList();
      try
      {
      db = getProductDb();
    view = db.getView("vaPNumber");
      Document doc2, doc = view.getFirstDocument();
      while(doc != null)
      {
    product = getProductFromDocument(doc);
    tempList.add(product);
    doc2 = doc;
    doc = view.getNextDocument(doc);
    doc2.recycle();
    }
    view.recycle();
    db.recycle();
      }catch(NotesException e){e.printStackTrace();}
    return tempList.toArray();
      }
    private Product getProductFromDocument(Document doc)
    {
    Product product = null;
    try
    {
    String name = doc.getItemValueString("ProductName");
    String description = doc.getItemValueString("ProductDescription");
    double price = doc.getItemValueDouble("ProductPrice");
    int productNumber = doc.getItemValueInteger("productNumber");
    product = new Product();
    product.setNumber(productNumber);
    product.setName(name);
    product.setPrice(price);
    product.setDescription(description);
    }
    catch(Exception e)
    {}
    return product;
    }
    private Database getProductDb()
    {
    Database db = null;
    try{
    db = session.getDatabase("","itso\\products.nsf");
    }catch(NotesException e){}
    return db;
    }
    public Product getProduct(double productNumber)
    {
    Product product = null;
      try
      {
        Database db = getProductDb();
    View view = db.getView("vaPNumber");
      Document doc = view.getDocumentByKey(new Double(productNumber), true);
        if(doc != null) {
          product = getProductFromDocument(doc);
          doc.recycle();
          doc = null;
        }
      view.recycle();
      db.recycle();
      }catch(NotesException e){}
      return product;
    }
    }

    Мы можем использовать новый Web-сервис, названный ProductService из Rational Application Developer, как показано на рис 3.12.

    (рис 3.12) Исполнение операции WSDL getProduct

    Пример 3.9 выводит контекст ответа SOAP, полученный от сервера Lotus Domino для определенного номера продукта, который мы использовали для активирования операции WSDL getProduct.

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    - <soapenv:Body>
    - <ns1:getProductResponse xmlns:ns1="urn:DefaultNamespace"
    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
      <getProductReturn href="#id0" />
      </ns1:getProductResponse>
    - <multiRef xmlns:ns2="urn:DefaultNamespace"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" id="id0" soapenc:
    root="0"
    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:
    type="ns2:Product">
    <description xsi:type="xsd:string">This is the basic Redbook offering.</description>
    <name xsi:type="xsd:string">Basic Redbook</name>
    <number xsi:type="xsd:int">20501</number>
    <price xsi:type=""xsd:double">102.0</price>
    </multiRef>
    </soapenv:Body>
    </soapenv:Envelope>

    У Web-сервиса ProductService, который мы только что создали, есть и другая операция, отправляющая набор объектов продуктов в виде массива, которая называется getAll-Products. Пример 3.10 наглядно иллюстрирует этот процесс. Его сообщения SOAP имеют формат RPC/encoded.

    - <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    - <soapenv:Body>
    - <ns1:getAllProductsResponse xmlns:ns1="urn:DefaultNamespace"
    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    - <getAllProductsReturn xmlns:soapenc="http://schemas.xmlsoap.org/soap/
    encoding/"
    soapenc:arrayType="xsd:anyType[9]" xsi:type="soapenc:Array">
      <item href="#id0" />
      <item href="#id1" />
      <item href="#id2" />
      <item href="#id3" />
      <item href="#id4" />
      <item href="#id5" />
      <item href="#id6" />
      <item href="#id7" />
      <item href="#id8" />
      </getAllProductsReturn>
      </ns1:getAllProductsResponse>
    - <multiRef xmlns:ns2="urn:DefaultNamespace"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" id="id1" soapenc:
    root="0"
    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:
    type="ns2:Product">
      <description xsi:type="xsd:string">Redpaper mid-tier line available at
    newsagents and
    department stores.</description>
      <name xsi:type="xsd:string">Redpaper Deluxe</name>
      <number xsi:type="xsd:int">10002</number>
      <price xsi:type="xsd:double">2299.0</price>
      </multiRef>
    - <multiRef xmlns:ns3="urn:DefaultNamespace"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" id="id8" soapenc:
    root="0"
    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:
    type="ns3:Product">
      <description xsi:type="xsd:string">The best Redbook money can buy.</
    description>
      <name xsi:type="xsd:string">Redbook Plus</name>
      <number xsi:type="xsd:int">45500</number>
      <price xsi:type="xsd:double">50000.0</price>
      </multiRef>
    и так далее.......
    - <multiRef xmlns:ns10="urn:DefaultNamespace"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" id="id6" soapenc:
    root="0"
    soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:
    type="ns10:Product">
      <description xsi:type="xsd:string">The ultimate Redbook experience.</
    description>
      <name xsi:type="xsd:string">Redbook Supreme</name>
      <number xsi:type="xsd:int">20564</number>
      <price xsi:type="xsd:double">1000.0</price>
      </multiRef>
      </soapenv:Body>
      </soapenv:Envelope>

    3.7 Экспортирование документа WSDL

    Документы WSDL экспортируют для того, чтобы предоставить покупателю информацию о том, как использовать созданные Web-сервисы. Во многих случаях инструменты, с помощью которых осуществляется создание клиентов Web-сервисов, могут автоматически генерировать код из документа WSDL.

    Для того чтобы экспортировать документ WSDL, выполните следующие действия:

  • Откройте базу данных ITSO Web Services в Domino Designer и выберите Shared Code => Web Services (Общий код $$\Rightarrow$$ Web-сервисы).
  • Выберите ProductService и щелкните по кнопке Export WSDL (Экспортировать документ WSDL).
  • После этого будет сгенерирован файл .
  • (рис 3.13) Экспортирование документа WSDL

    3.8 Импортирование документа WSDL

    Если вы импортируете документ WSDL, описательный класс генерируется на основе содержания документа WSDL. Общедоступные прототипы методов, функций и подстановок в классе соответствуют операциям Web-сервиса, определенным для первого элемента <port> первого элемента <service> в документе WSDL. Другие классы или типы ссылаются на прототипы методов, которые, возможно, также будут сгенерированы на основании содержимого документа WSDL вместе с общедоступными элементами данных. Если вы измените прототип интерфейса, соответствующий документ WSDL также изменится, когда Web-сервис будет сохранен. Вы можете отслеживать подобные изменения с помощью свойства "Warn if the WSDL interface is modified" (Предупреждать, если интерфейс WSDL был изменен).

    Бизнес-партнеры компании ITSO Electronics, а, возможно, и покупатели, в свою очередь, могут обеспечивать компанию документом WSDL, который она может использовать для создания Web-сервисов. Вы можете импортировать существующий документ WSDL, чтобы сгенерировать каркас Web-сервиса. Каркасный код соответствует описанию Web-сервиса. Затем вам необходимо добавить код реализации.

    Для того чтобы импортировать документ WSDL, выполните следующее:

  • Откройте базу данных ITSO Web Services в Domino Designer, затем выберите Shared Code => Web Services.
  • Щелкните по кнопке ).(рис 3.14) Импортирование документа WSDL
  • В результате импортирования документа WSDL будет сгенерирован каркасный код, который в нашем сценарии сгенерирован на языке LotusScript, как показано в примере 3.11. Затем мы открыли окно свойств Web Service, поставили галочку рядом с опцией ).
    (рис 3.11) Импортирование документа WSDL: окно свойств Web Service(рис 3.15) Каркасный код, сгенерированный после импортирования документа WSDL%INCLUDE "lsxsd.lss"
    Class ArrayOfProduct_Holder As INOUT_HOLDER
    Public Value() As Product
    End Class
    Class Product
    Public description As XSD_STRING
    Public name As XSD_STRING
    Public number As Long
    Public price As Double
    Sub NEW
    End Sub
    End Class
    Class ProductService
    Sub NEW
    End Sub
    Function getAllProducts() As ArrayOfProduct_Holder
    End Function
    Function getProduct(productNumber As Double) As Product
    End Function
    End Class
  • 3.9 Работа с исключениями и ошибками в Web-сервисах

    Операции также могут возвращать ошибки посредством подкласса ошибок, который соответствует некоторому сообщению <wsdl:fault>, выбранному для определенной операции в документе WSDL, или посредством прямого использования базового класса WS_FAULT (LotusScript), или класса lotus.domino.types.Fault, или класса java.lang.Exception(Java).

    Замечание Любые ошибки в методе описания сервиса на языке LotusScript (т. е. любой основной класс или подкласс WS_FAULT ) должны фигурировать в конце списка параметров метода.

    Ошибки для метода описания сервиса на языке Java возникают в стандартных предложениях Java.

    Для получения дополнительной информации о том, как работать с ошибками, используя язык LotusScript см. п. 3.12, "Использование Web-сервисов с помощью LS2J".

    3.10 Безопасность в Web-сервисах

    Угрозы безопасности Web-сервисов, определенных в приложении ITSO Electronics, подразумевают угрозу всей системе, на которой базируется Web-сервис, приложению и инфраструктуре сети в целом. Для обеспечения защиты Web-сервисов необходим целый спектр механизмов защиты, основанных на языке XML, так как только благодаря им становится возможным решение проблем, касающихся аутентификации, ролевого контроля доступа к базам данных, реализации принципов обеспечения безопасности, а также безопасности уровня сообщений, которая выполняет роль посредника.

    В настоящий момент не существует общепринятых спецификаций безопасности Web-сервисов. Поэтому разработчики могут либо создавать службы, которые не используют подобных возможностей, либо разрабатывать специальные узкопрофильные программы, которые предположительно смогут решать проблемы функциональной совместимости.

    Для применения Web-сервисов могут потребоваться механизмы защиты "точка-точка" или сквозные механизмы защиты, или оба механизма в зависимости от степени угрозы или риска. Традиционные механизмы безопасности, построенные на основе соединений "точка-точка", возможно, не смогут справиться с потребностями в сквозной защите Web-служб. Тем не менее, безопасность – это баланс между оцененным риском и затратами на противодействие. В зависимости от допускаемого риска использования защита, обеспечиваемая соединением "точка-точка", работающая на уровне переноса данных, позволяет обеспечить достаточными мерами безопасности.

    В архитектуре приложения ITSO Electronics существует три фундаментальных принципа, относящихся к безопасности: ресурсы, которые должны быть защищены; механизмы, благодаря которым обеспечивается эта защита (т. е. политика защиты); и политики, которые представляют собой обрабатываемые компьютерами документы, которые, описывают ограничения на этих ресурсах. Для продолжения дискуссии о безопасности применения Web-сервисов обратитесь к руководству Web Service Architecture, которое доступно по следующему адресу в Интернете: http://www.w3.org/TR/2004/NOTE-ws-arch-20040211

    Web-сервис Lotus Domino 7 обладает теми же возможностями защиты, что и агент. Уровень защиты Web-сервиса устанавливается в закладке Security (Безопасность) окна свойств Web service. В приведенном ниже списке описываются параметры, доступные в закладке Security.

  • Run as web user (Запускать от лица Web-пользователя): код Java или LotusScript запускается с реальным именем пользователя, который запустил Web-сервис.
  • Run on behalf of (Запускать от лица): код Java или LotusScript запускается на полномочиях определенного пользователя. Тем не менее, подписчик Web-сервиса должен обладать неограниченными правами на сервер или правом запускать Web-сервисы от лица любого пользователя.
  • Set runtime security level (Установить уровень защиты выполнения) (один из перечисленных ниже):
  • Do not allow restricted operations (Не разрешать выполнение операций с ограниченным доступом);
  • Allow restricted operations (Разрешать выполнение операций с ограниченным доступом);
  • Allow restricted operations with full administration rights (Разрешать выполнение операций с ограниченным доступом с полными правами администрирования).
  • Default access for this web service (Доступ по умолчанию к этому Web-сервису):
  • All readers and above (Все читатели и выше). Вы можете выбрать или снять этот параметр.
  • Enumerated (Перечисленные). Если вы убрали галочку рядом с параметром All readers and above, то с помощью этого параметра вы можете выбрать тех, кому вы хотите предоставить доступ по умолчанию.
  • Allow Public Access users to use this web service (Разрешить пользователям открытого доступа применять этот Web-сервис). Если выбран этот параметр, пользователи, обладающие открытым доступом к документам в базе данных, получают доступ по умолчанию.
  • 3.11 Использование Web-сервисов с помощью Java

    На момент написания этой книги Lotus Domino 7.0 обеспечивал, хотя и не в полном объеме, использование Web-сервисов. Тем не менее, вспомогательным бизнес-требованием, предъявляемым к приложению ITSO Electronics, является предоставление доступа к ценовым данным, располагающимся за границами Lotus Domino, что, в свою очередь, диктует необходимость использования Web-сервисов в этом приложении. В нашем сценарии компания ITSO Electronics решила применить программный продукт с открытым исходным кодом

    Для того чтобы проиллюстрировать использование Web-сервисов, в нашем сценарии мы создали отдельную базу данных в приложении ITSO Electronics, которую назвали WS Consumer. В этой базе данных содержится агент, который будет использовать сложный Web-сервис, созданный нами ранее.

    Замечание Web-сервисы могут быть добавлены к любой базе данных Lotus Notes и Domino. Но для достижения целей, поставленных в этой книге, все Web-сервисы добавлены к отдельным базам данных в приложении ITSO Electronics, которые называются webservices.nsf и wsconsumer.nsf.

    Приведенная ниже последовательность действий наглядно иллюстрирует создание агента, использующего Web-сервис.

  • Загрузите самую последнюю версию Apache SOAP по следующей ссылке: http://ws.apache.org/soap/
  • Извлеките загруженный файл во временную директорию, в нашем сценарии в качестве такой папки мы использовали папку c:\soap.
  • Экспортируйте сложный Web-сервис ProductService (находящийся в базе данных Web Services) в документ WSDL. В экспортированном документе WSDL содержится вся информация, необходимая для использования Web-сервиса.
  • Откройте документ WSDL в текстовом редакторе. Документ WSDL содержит информацию, описывающую сложный тип данных, возвращаемых этим Web-сервисом, как видно из примера 3.12. В нашем случае этот сложный тип данных называется Product. Сложный элемент Type показывает свойства объекта Product, к которым относятся описание, название, номер и цена.
    <wsdl:types>
      <schema targetNamespace="urn:DefaultNamespace" xmlns="http://www.w3.org/2001/
    XMLSchema"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
    <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
    <complexType name="Product">
      <sequence>
        <element name="description" nillable="true" type="xsd:string"/>
        <element name="name" nillable="true" type="xsd:string"/>
        <element name="number" type="xsd:int"/>
        <element name="price" type="xsd:double"/>
      </sequence>
    </complexType>
    <complexType name="ArrayOfProduct">
      <complexContent>
        <restriction base="soapenc:Array">
         <attribute ref="soapenc:arrayType" wsdl:arrayType="impl:Product[]"/>
        </restriction>
       </complexContent>
      </complexType>
     </schema>
    </wsdl:types>
  • Откройте новую базу данных WS Consumer в Domino Designer, выберите Shared Code => Agents (Общий код $$\Rightarrow$$ Агенты), после чего щелкните по кнопке New agent (Создать агент).
  • В поле .(рис 3.16) Окно свойств ConsumerWS Agent
  • Закройте окно свойств Agent, затем выберите язык кода Java.
  • Нам необходимо создать класс JavaBean, представляющий сложный тип данных Product, определенный в документе WSDL. Для облегчения этой операции мы воспользуемся возможностью импортирования WSDL для автоматической генерации класса JavaBean. После этого нам необходимо выбрать Shared Code => Web Service (Общий код $$\Rightarrow$$ Web-сервис) и щелкнуть по кнопке New Web Service (Создать Web-сервис).
  • Закройте окно свойств Web Service и убедитесь в том, что язык описания Web-сервиса установлен на Java. Щелкните по кнопке Import WSDL (Импортировать WSDL), затем выберите созданный ранее документ WSDL. В результате импортирования этого документа будут автоматически созданы классы JavaBeansTM.
  • Выделите и скопируйте код Java для Product.java.
  • Вернитесь к агенту и щелкните по кнопке New Class (Создать класс). Затем замените класс Untitled.java скопированным кодом Product.java, так же, как это сделано в примере 3.13.
  • Сохраните агент ConsumeWS и убедитесь в том, что он был успешно скомпилирован.

    Щелкните по кнопке ). Перейдите к нужной директории библиотеки SOAP LIB, в нашем случае эта директория находилась по следующему пути: c:\soap\soap-2_3_1\lib. В качестве типа файла выберите Archive (Архивный), щелкните по кнопке Add/Replace File(s) (Добавить/Заменить файлы), далее нажмите ОК.

    (рис 3.17) Окно Organize Java Agent Files
  • Вам необходимо код JavaAgent.java по умолчанию заменить своим собственным, чтобы приступить к использованию Web-сервиса, который в нашем сценарии представлен в примере 3.14. Убедитесь в том, что в классе JavaAgent.java есть переменные URL и soapAction. Эти переменные должны указывать на расположение вашего приложения.
  • Сохраните агент ConsumeWS.
  • Вернитесь к новому Web-сервису и закройте его без сохранения.
  • Откройте клиент Lotus Notes и выберите базу данных WS Consumer. Перейдите к .(рис 3.18) Окно Java, в котором отображен результат работы Web-сервисаЕсли окно не открылось, выберите File => Tools => Show Java Debug Console (Файл $$\Rightarrow$$ Сервис $$\Rightarrow$$ Показать консоль отладки Java) для получения дополнительной информации.
  • public class Product {
    private java.lang.String description;
    private java.lang.String name;
    private int number;
    private double price;
    public Product() {
    }
    public java.lang.String getDescription() {
    return description;
    }
    public void setDescription(java.lang.String description)
    this.description = description;
    }
    public java.lang.String getName() {
    return name;
    }
    public void setName(java.lang.String name) {
    this.name = name;
    }
    public int getNumber() {
    return number;
    }
    public void setNumber(int number) {
    this.number = number;
    }
    public double getPrice() {
    return price;
    }
    public void setPrice(double price) {
    this.price = price;
    }
    private java.lang.Object __equalsCalc = null;
    public synchronized boolean equals(java.lang.Object obj) {
    if (!(obj instanceof Product)) return false;
    Product other = (Product) obj;
    if (obj == null) return false;
    if (this == obj) return true;
    if (__equalsCalc != null) {
    return (__equalsCalc == obj);
    }
    __equalsCalc = obj;
    boolean _equals;
    _equals = true 
    ((this.description==null  other.getDescription()==null) |
     (this.description!=null 
      this.description.equals(other.getDescription()))) 
    ((this.name==null  other.getName()==null) ||
     (this.name!=null 
      this.name.equals(other.getName()))) 
    this.number == other.getNumber() 
    this.price == other.getPrice();
    __equalsCalc = null;
    return _equals;
    }
    private boolean __hashCodeCalc = false;
    public synchronized int hashCode() {
    if (__hashCodeCalc) {
    return 0;
    }
    __hashCodeCalc = true;
    int _hashCode = 1;
    if (getDescription() != null) {
    _hashCode += getDescription().hashCode();
    }
    if (getName() != null) {
    _hashCode += getName().hashCode();
    }
    _hashCode += getNumber();
    _hashCode += new Double(getPrice()).hashCode();
    __hashCodeCalc = false;
    return _hashCode;
    }
    }
    import lotus.domino.*;
    import java.io.*;
    import java.util.*;
    import java.net.*;
    import org.w3c.dom.*;
    import org.apache.soap.util.xml.*;
    import org.apache.soap.*;
    import org.apache.soap.encoding.*;
    import org.apache.soap.encoding.soapenc.*;
    import org.apache.soap.rpc.*;
    import javax.swing.*;
    public class JavaAgent extends AgentBase
    {
        public void NotesMain()
        {
            try
            {
                Session session = getSession();
                AgentContext agentContext = session.getAgentContext();
    
    URL url = new URL("http://domino7appdev.cam.itso.ibm.com/itso/webservices.nsf/
    ProductService?WSDL");
    
    String soapAction ="http://domino7appdev.cam.itso.ibm.com/itso/webservices.nsf/
    ProductService?WSDL";
                Call call = new Call();
                BeanSerializer beanSerializer = new BeanSerializer();
                SOAPMappingRegistry smRegistry = new SOAPMappingRegistry();
                smRegistry.mapTypes(Constants.NS_URI_SOAP_ENC, new QName(
                        "urn:DefaultNamespace", "Product"), Product.class,
    beanSerializer,
                        beanSerializer);
                String targetNamespace = "urn:DefaultNamespace";
                call.setSOAPMappingRegistry(smRegistry);
                call.setTargetObjectURI(targetNamespace);
                call.setMethodName("getAllProducts");
                call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
                Response resp = null;
                try
                {
                    resp = call.invoke(url, soapAction);
                } catch (SOAPException e)
                {
                    e.printStackTrace();
    
    System.err.println("SOAP Exception code: " + e.getFaultCode() + " message: " + e.ge
                    return;
                }
                if (!resp.generatedFault())
                {
                    Parameter ret = resp.getReturnValue();
                    Product[] products = (Product[]) ret.getValue();
                    buildGUI(products);
                }
      else
                {
                    Fault fault = resp.getFault();
    
    System.err.println("SOAP Fault, " + fault.getFaultCode() + " " + fault.
    getFaultS
                }
            } catch (Exception e)
            {
                e.printStackTrace();
            }
        }
        private void buildGUI(Product[] products)
        {
              StringBuffer sb = new StringBuffer();
              String newLine = "<br>";
              for(int i = 0; i < products.length; i++)
              {
              sb.append(newLine + newLine);
    
    sb.append(products[i].getName() + " (" + products[i].getNumber() + ")" +
    newLine);
              sb.append( " * " + products[i].getDescription());
              sb.append(newLine + " * " + products[i].getPrice());
    }
              JFrame frame = new JFrame("Web service content");
              frame.getContentPane().add(new JScrollPane(new JLabel("<html>" + sb.
    toString() + "</html>")));
              frame.pack();
              frame.setVisible(true);
    }
    }

    3.12 Использование Web-сервисов с помощью LS2J

    В этом разделе мы расскажем о следующем:

  • как использовать Web-сервис с помощью LotusScript;
  • как с помощью LS2J обращаться к коду Java из агента LotusScript;
  • как работать с исключениями или ошибками, возвращаемыми назад от Web-сервисов;
  • об аутентификации и Web-сервисах.
  • 3.12.1 Несколько слов о LS2J

    LS2J представляет собой интерфейс, позволяющий переводить данные из типов данных Java в типы данных LotusScript и позволяет LotusScript выполнять методы объектов Java. Благодаря LS2J LotusScript получает способность создавать объекты Java так, будто они были родными для среды LotusScript.

    В этом сценарии мы добавили агент LotusScript к базе данных WS Consumer. Агент использует код Java из библиотеки скриптов, для того чтобы использовать Web-сервис.

    Web-сервис, который мы используем, способен выполнять одно из двух действий:

  • возвращать имя текущего пользователя;
  • возвращать объект WS_FAULT, для того чтобы проиллюстрировать, как Web-сервисы способны отправлять коды ошибок обратно к клиенту.
  • 3.12.2 Создание Web-сервиса

    Перечисленные ниже этапы показывают, как создать Web-сервис с помощью LS2J. В этом разделе описывается создание Web-сервиса, а в последующих речь пойдет о создании библиотеки скриптов Java и о том, как она используется в нашем агенте LotusScript через LS2J. Выполните приведенную ниже последовательность действий.

  • Откройте базу данных Web Services в Domino Designer.
  • Щелкните по кнопке New Web Service.
  • Убедитесь, что установлен язык кода LotusScript.
  • Перейдите к разделу Declarations и перепечатайте код, представленный в примере 3.15.
    Dim session As NotesSession
    Class UserInfo
        Function getUserName ( Fault1 As WS_FAULT)
            Set session = New NotesSession
            Dim doc As NotesDocument
            Set doc = session.DocumentContext
            If Cint(Rnd() * 10) > 5 Then
               getUserName = doc.remote_user(0)
            Else
               Call Fault1.setFault(True) ' необходимо для ошибочной активации
               Call Fault1.setFaultString("SUCCESS, We send a FAULT on purpose")
            End If
        End Function
    End Class
  • Откройте окно свойств Web-сервиса и в поле .
  • Сохраните и закройте Web-сервис.
  • (рис 3.19) Окно свойств LS2J Web Service UserInfo

    3.12.3 Создание библиотеки скриптов, необходимой для использования Web-сервиса с помощью Java

    Теперь нам необходимо создать библиотеку скриптов, содержащую класс Java, который будет использовать Web-сервис и сделает его доступным нашему агенту LotusScript через LS2J. Для того чтобы настроить класс Java, необходимо выполнить следующую последовательность действий:

  • Откройте базу данных WS Consumer в Domino Designer.
  • В навигационной панели выберите Shared Code (Общий код) и щелкните по кнопке New Java Library (Новая библиотека Java).
  • В открывшемся окне щелкните по кнопке ). Если у вас отсутствует файл Apache soap.jar, необходимо вернуться к п. 3.11, "Использование Web-сервисов с помощью Java" для получения дополнительной информации о том, как загрузить Apache SOAP.
  • Сохраните библиотеку скриптов под именем ConsumeWSLibrary.
  • Замените код для библиотеки по умолчанию кодом, приведенным в примере 3.16.
  • Важно Приведенные ниже строчки из примера 3.16 должны быть скорректированы и соответствовать URL вашей базы данных:
    URL url = new URL("http://domino7appdev.cam.itso.ibm.com/itso/
    webservices.nsf/ProductService?WSDL");
    String soapAction ="http://domino7appdev.cam.itso.ibm.com/itso/
    webservices.nsf/ProductService?WSDL";
    (рис 3.16) Импортирование архива Java, который будет использован с LS2J(рис 3.20) Код Java, необходимый для использования Web-сервисов средой LS2Jimport java.io.*;
    import java.util.*;
    import java.net.*;
    import org.w3c.dom.*;
    import org.apache.soap.util.xml.*;
    import org.apache.soap.*;
    import org.apache.soap.encoding.*;
    import org.apache.soap.encoding.soapenc.*;
    import org.apache.soap.rpc.*;
    import org.apache.soap.transport.http.SOAPHTTPConnection;
    public class WSConsumer
    {
        public String getValue(String userName, String password)
        {
            try
            {
    URL url = new URL("http://domino7appdev.cam.itso.ibm.com/itso/webservices.nsf/
    UserInfo?WSDL");
    
    String soapAction ="http://domino7appdev.cam.itso.ibm.com/itso/webservices.nsf/
    UserInfo?WSDL";
                Call call = new Call();
                SOAPHTTPConnection hc = new SOAPHTTPConnection();
      hc.setUserName(userName);
         hc.setPassword(password);
                call.setSOAPTransport(hc);
                SOAPMappingRegistry smRegistry = new SOAPMappingRegistry();
                String targetNamespace = "urn:DefaultNamespace";
                call.setSOAPMappingRegistry(smRegistry);
                call.setTargetObjectURI(targetNamespace);
                call.setMethodName("getUserName");
                call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
                Response resp = null;
                try
                {
                    resp = call.invoke(url, soapAction);
                } catch (SOAPException e)
                {
                    e.printStackTrace();
    return ("SOAP Exception code: " + e.getFaultCode() + " message: " +
    e.getMessage());
                }
                if (!resp.generatedFault())
                {
                    Parameter ret = resp.getReturnValue();
    return ret.getValue() + "";
                }
      else
                {
                    Fault fault = resp.getFault();
                    return ("SOAP Fault, " + fault.getFaultCode() + " " + fault.
    getFaultString());
                }
            } catch (Exception e)
            {
                e.printStackTrace();
            }
            return null;
        }
    }

    3.12.4 Создание агента, используя язык LotusScript

    Наконец нам необходимо создать агент LotusScript и использовать только что созданную библиотеку через LS2J.

  • В панели Navigation выберите Shared Code => Agents.
  • Щелкните по кнопке New Agent. В окне свойств нового агента, в поле Name, введите LotusScriptConsumeWS, а в выпадающем списке Target раздела Runtime выберите None. Закройте окно свойств.
  • Измените язык на LotusScript.
  • В Declarations замените код по умолчанию кодом, приведенным в примере 3.17.
  • В Initialize замените код по умолчанию кодом из примера 3.18.Замечание Скорректируйте строчку value = myObject.getValue("The UserName", "The Password"), введя правильное имя пользователя и пароль.
    Option Public
    Use "ConsumeWSLibrary"
    Uselsx "*javacon"
    Sub Initialize
    Dim mySession As JavaSession
    Dim myClass As JavaClass
    Dim myObject As JavaObject
    Set mySession = New JavaSession ()
    Set myClass = mySession.GetClass("WSConsumer")
    Set myObject = myClass.CreateObject
    Dim value As String
    value = myObject.getValue("The UserName", "The Password")
    Msgbox value
    End Sub
  • Сохраните и закройте агент.
  • В клиенте Lotus Notes запустите только что созданный агент. Если вы увидите сообщение, которое представлено на рис 3.21, то оно, скорее всего, вызвано тем, что вы не обеспечили код точным именем пользователя и паролем.
  • (рис 3.21) Сообщение об ошибке, возникшей при использовании Web-сервиса с помощью LS2J

    Если агент смог использовать ваш Web-сервис, вы увидите сообщение, представленное на рис 3.22.

    (рис 3.22) Web-сервис был успешно использован с помощью LS2J

    3.12.5 Аутентификация и Web-сервисы

    В Lotus Notes и Domino 7 Web-сервис обладает теми же возможностями защиты, что и агент. В примере 3.19 мы использовали базовую аутентификацию HTTP, для того чтобы защитить наш Web-сервис. Apache SOAP позволяет нам отправлять имена пользователей и пароли в виде SOAP-запросов, добавляя экземпляр класса SOAPHTTPConnection к объекту Call.

    Call call = new Call();
    SOAPHTTPConnection hc = new SOAPHTTPConnection();
    hc.setUserName(userName);
    hc.setPassword(password);
    call.setSOAPTransport(hc);

    3.13 Какой стиль WSDL мне следует использовать?

    В документе WSDL содержится XML-код, который описывает Web-сервис. Привязка WSDL описывает то, как сервис связан с протоколом обмена сообщениями. Привязка WSDL SOAP может быть осуществлена либо при помощи вызова удаленных процедур (RPC), либо при помощи документной привязки. Привязка SOAP также может употребляться как в кодированном виде, так и в литеральном виде. Таким образом, у разработчика приложений Lotus Domino есть четыре типа/моделей использования на выбор:

  • вызов удаленных процедур/кодированный (RPC/encoded);
  • вызов удаленных процедур/литеральный (RPC/literal);
  • документальный/литеральный (Document/literal);
  • заключенный в оболочку (Wrapped).
  • Терминология "RPC против документального" может сбивать с толку, так как эти термины подразумевают, что тип RPC следует использовать для программируемых моделей RPC и что документальный тип нужно использовать для документальных программируемых моделей или для программируемых моделей обмена сообщениями. Тем не менее, в данном случае все эти заблуждения бессмысленны, так как тип не имеет ничего общего с программируемыми моделями. Типы только диктуют то, как переводить привязку WSDL в сообщение SOAP. Подобно этому, типы кодированный и литеральный имеют значение только в привязке WSDL-к-SOAP.

    Вернуться к учебному плану