Web-службы Lotus Notes/Domino 7

Роберт Перрон, разработчик документации, IBM

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

Lotus Domino отображает интерфейс WSDL как Web-службу, которая может быть внедрена в код LotusScript и Java. Для использования Web-службы она должна быть размещена на сервере Domino с открытым HTTP доступом. (Проверить работу Web-службы можно через HTTP-сессию в клиентском предварительном просмотре Notes.) Доступ производится через одну из следующих команд Domino URL:

  • ?OpenWebService запрашивает Web-службу путём получения ответа на SOAP-сообщение, отправленное методом HTTP POST. HTTP GET (например, запрос из браузера) возвращает название службы и выполняемые ей операции.
  • ?WSDL в качестве ответа на HTTP GET возвращает документ WSDL.

В этой статье описан компонент Web-службы в Lotus Notes/Domino 7, приведены примеры в LotusScript и Java. Статья рассчитана на опытных разработчиков в среде Notes, знакомых с LotusScript и Java.

Пример

Приведём простой пример. Дано имя базы данных, имя отображения, а также номер документа; наша операция возвращает содержимое элемента "Subject". Назовём её getNthSubject.

Диаграмма getNthSubject

Рис. 1. Диаграмма getNthSubject.

Чтоб открыть доступ к операции окружающему миру, мы публикуем её в Web-службе под названием GetSubject. В GetSubject может содержаться сколько угодно операций. Например, нам могут понадобиться операции getFirstSubject и getLastSubject. Однако давайте пока что разберёмся с нашим примером, операцией getNthSubject. Ниже приведена выдержка из документа WSDL, описывающего содержащую данную операцию Web-службу. Просмотрите этот листинг, читая комментарии ниже.

<wsdl:message name=
        "getNthSubjectRequest"> (4)
  <wsdl:part name="dbname" type="xsd:string"/> (5)
  <wsdl:part name="viewname" type="xsd:string"/> (5)
  <wsdl:part name="n" type="xsd:int"/> (5)
</wsdl:message>

<wsdl:message name="getNthSubjectResponse"> (4)
 <wsdl:part name="getNthSubjectReturn" type="xsd:string"/> (6)
</wsdl:message>

<wsdl:portType name="GetSubjectPortType"> (1)
  <wsdl:operation name="getNthSubject"
   parameterOrder="dbname viewname n"> (2)
  <wsdl:input message="impl:getnthSubjectRequest" name="
    GetNthSubjectRequest"/> (3)
  <wsdl:output message="impl:getNthSubjectResponse" name="
    GetNthSubjectResponse"/> (3)
  </wsdl:operation>
</wsdl:portType>

Сначала взгляните на определяющий набор операций службы элемент portType(1). У нашей службы только один элемент portType с единственной операцией getNthSubject(2). У операции есть два "сообщения"(3) - одно для входа, одно для выхода. Сообщения определены в элементах message(4). Как мы видим, входящее сообщение состоит из трех частей(5): две строки с названиями dbname и viewname, и переменная n типа int. Исходящее сообщение состоит из единственной строки под названием getNthSubjectReturn(6).

Таким образом, у нас есть одна операция с тремя входящими частями и одной исходящей, которая довольно ясно указывает на процедуру с тремя параметрами только для чтения и одним возвращаемым значением. В LotusScript такая процедура была бы определена следующей функцией:

Public Function getNthSubject(dbname As String, viewname As String, n As Long) As String

И в Java следующим методом:

public String getNthSubject(String dbname, String viewname, int n)

Компонент Web-службы

Для создания компонента Web-службы в Domino Designer есть несколько путей. Мы можем написать его непосредственно в LotusScript или Java. В таком случае при сохранении компонента генерируется документ WSDL, отражающий код LotusScript или Java. Или же мы можем импортировать уже существующий документ WSDL. В этом случае в соответствии с выполняемыми в WSDL операциями генерируются LotusScript или Java. В компоненте Web-службы сохраняется как код, так и документ WSDL. Если публичный интерфейс не меняется, документ WSDL тоже остаётся как есть. Если же в нашем коде мы меняем что-то изменяющее публичный интерфейс, то изменится и WSDL.

В Domino Designer компонент Web-службы находится под закладкой Agents в закладке Shared Code. Окно конструктора Web-службы очень похоже на окно конструктора агента. Чтобы создать новую Web-службу, нажмите на кнопку New Web Service. Для редактирования уже существующей Web-службы дважды щёлкните по ней.

Новая Web-служба

Рис. 2. Новая Web-служба

В окне свойств Web-службы, как и в окне агента, три закладки. Вот основная закладка:

Окно свойств Web-службы

Рис. 3. Окно свойств Web-службы

Поле name (имя) должно быть заполнено, а поля Alias (псевдоним) и Comment (комментарий) можно не заполнять. Также вы можете выбрать, необходимо ли предупреждать вас в том случае, если в результате изменения программного кода будет генерироваться новый WSDL.

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

Закладка Security (безопасность) почти такая же, как и у агентов, детальнее мы её обсудим позже.

В закладке Advanced (дополнительно) содержится дополнительная информация для определения Web-службы и генерации WSDL. Детальнее мы её обсудим позже.

Окно редактора такое же, как и у агентов. Справа выпадающее меню, в котором можно выбрать LotusScript или Java. На рисунке ниже выбрана Java. Слева окно объектов и ссылок.

Web-служба (Java)

Рис. 4. Web-служба (Java)

Чтобы создать новую Web-службу, опираясь на уже существующий WSDL-документ, используйте кнопку Import WSDL (Импорт WSDL). Кнопка Show WSDL компилирует любые внесённые в Web-службу изменения и показывает отображающий её публичный интерфейс документ WSDL. Кнопка Export WSDL компилирует любые внесённые в Web-службу изменения и экспортирует отображающий её публичный интерфейс документ WSDL. Также компиляция запускается при сохранении либо закрытии Web-службы. WSDL заново генерируется только в случае изменения публичного интерфейса.

Основы написания кода

Код Web-службы содержит следующие элементы:

  • Определение класса для исполняемого кода. Этот класс должен быть указан в поле класс PortType на основной закладке окна свойств, он должен быть публичным.
  • Внутри класса должно быть процедурное (функция, метод) определение для каждой операции Web-службы. Эти процедуры должны быть публичными. Вспомогательные процедуры, которые не должны быть видны через интерфейс, должны быть закрытыми.
  • Включение lsxsd.lss для LotusScript и импорт lotus.domino.types.* для Java.
  • Инициализация объекта NotesSession (LotusScript) или Session (Java) в том случае, если нужен доступ к Domino Objects. Это лучше делать для LotusScript в новом блоке, а для Java конструктором без параметров. Чтоб получить объект типа Session в Java, мы используем WebServiceBase.getCurrentSession(). Ещё нам иногда может понадобиться объект AgentContext, который мы получаем при помощи Session.getAgentContext(). WebServiceBase эквивалентен JavaAgent, к которому у Web-службы нет доступа. Единственный работающий здесь метод - это статичный getCurrentSession().

Ниже приведён шаблон кода LotusScript с Web-службой, содержащей одну операцию. Это та самая операция с тремя входящими параметрами и одним исходящим из примера выше.

Option Public
%INCLUDE "lsxsd.lss"
Dim s As NotesSession
Class GetSubject
  Sub NEW
    Set s = New NotesSession
  End Sub
  Function getNthSubject(dbname As String, viewname As String, n As Long) As String
        ! Code for doing the operation goes here
  End Function
End Class

А здесь приведён шаблон кода Java с сос Web-службой, содержащей одну операцию. Конструктором должен быть конструктор по умолчанию (без параметров). Остальные конструкторы игнорируются.

import lotus.domino.*;
import lotus.domino.types.*;
public class GetSubject {
  Session s;
  public GetSubject() {
    s = WebServiceBase.getCurrentSession();
  }
  public String getNthSubject(String dbname, String viewname, int n) {
        // Здесь начинает код для выполнения операции
  }
}

Теперь мы расширим примеры, включив в них рабочий код. Ниже следует пример LotusScript:

Option Public
%INCLUDE "lsxsd.lss"

Dim s As NotesSession

Class GetSubject

  Sub NEW
    Set s = New NotesSession
  End Sub

  Function getNthSubject(dbname As String, viewname As String, n As Long) As String
    Dim db As NotesDatabase
    Dim view As NotesView
    Dim doc As NotesDocument
    Set db = s.GetDatabase("", dbname)
    If Not(db.IsOpen) Then
      getNthSubject = "Cannot open database " & dbname
      Exit Function
    End If
    Set view = db.GetView(viewname)
    If view Is Nothing Then
      getNthSubject = "Cannot open view " & viewname
      Exit Function
    End If
    Set doc = view.GetNthDocument(n)
    If doc Is Nothing Then
      getNthSubject = "Cannot get document " & n
      Exit Function
    End If
    If doc.HasItem("Subject") Then
      getNthSubject = doc.GetItemValue("Subject")(0)
    Else
      getNthSubject = "Document does not have Subject"
    End If
  End Function
End Class

Далее следует пример на Java:

import lotus.domino.*;
import lotus.domino.types.*;

public class GetSubject {

  Session s;

  public GetSubject() {
    s = WebServiceBase.getCurrentSession();
  }

  public String getNthSubject(String dbname, String viewname, int n) {
    String subject = null;
    try {
      Database db = s.getDatabase(null, dbname);
      if (!db.isOpen()) subject = "Cannot open database " + dbname;
      else {
        View view = db.getView(viewname);
        if (view == null) subject = "Cannot open view " + viewname;
        else {
          Document doc = view.getNthDocument(n);
          if (doc == null) subject = "Cannot get document " + n;
          else {
            if (doc.hasItem("Subject"))
              subject = doc.getItemValueString("Subject");
            else subject = "Document does not have Subject";
          }
        }
      }
    }
    catch(Exception e) {
      subject = e.toString();
      e.printStackTrace();
    }

    return subject;
  }
}

Обращение к Web-службе и проверка её работоспособности

Во-первых, Web-служба должна находиться на сервере Domino 7 с работающим HTTP-протоколом. Мы можем проверить работу элемента Web-службы, находящегося в Domino Designer. В начале необходимо в браузере или где-нибудь ещё (в форме, например) выбрать Design - Preview, чем запускается протокол HTTP. Если пользователь находится на том же компьютере, где и клиентская программа Notes, в качестве адреса компьютера используйте 127.0.0.1. Действуя в качестве пользователя, в адресной строке мы посылаем SOAP-сообщение в запросе к Web-службе Domino по протоколу HTTP POST. Адресная строка должна выглядеть приблизительно так:

http://rperron300pl.notesdev.ibm.com/Webservices2.nsf/GetSubject?OpenWebService

SOAP-сообщение должно выглядеть приблизительно так:

<SOAP-ENV:Envelope
 ENV="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 <SOAP-ENV:Body>
  <ns0:getNthSubject (1)
   SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
   xmlns:ns0="urn:DefaultNamespace">
   <dbname xsi:type="xsd:string">Webservices2</dbname> (2)
   <viewname xsi:type="xsd:string">Main View</viewname> (2)
   <n xsi:type="xsd:int">2</n> (2)
  </ns0:getNthSubject>
 </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

В данном примере в SOAP-сообщении определена выполняемая операция и входные значения для неё. Специфические элементы, вроде SOAP-ENV:body определены правилами построения WSDL, в частности - форматом SOAP-сообщения (см. раздел ниже "Дополнительные свойства" для получения более детальной информации).

В WebSphere SDK для Web-служб есть инструмент для создания запросов к Web-службам и просмотра результатов. Этот SDK работает под Eclipse. Должны быть установлены:

TWebSphere SDK на момент написания статьи не работает с Eclipse 3.0. Кроме того, для создания запросов можно использовать WebSphere Studio Application Developer. Последней является версия 5.1.2

Чтобы использовать WebSphere SDK, запустите Web Service Explorer (браузер Web-служб) через Run - Launch. После загрузки браузера Web-служб:

  1. Щёлкните на иконке WSDL Page (страница WSDL). Это третья иконка от показывающей направо стрелочки справа сверху. На панели навигации слева появится ссылка WSDL Main.
  2. Жмите на ссылку WSDL Main. На правой панели появится поле для ввода "Open WSDL".
  3. Введите адрес Web-службы с командой ?WSDL, например, http://rperron300pl.notesdev.ibm.com/Webservices2.nsf/GetSubject?WSDL, и щёлкайте на Go. На данном этапе браузер Web-служб должен прочитать документ WSDL, поэтому мы используем ?WSDL, а не ?OpenWebService.
  4. На правой панели появится меню со связанной информацией WSDL. В нём содержатся ссылки на операции, определённые Web-службой.
  5. Щёлкните на имени операции, например, getNthSubject. Появится диалоговое окно "Создать запрос к операции WSDL".
  6. Вводите значения параметров и щёлкайте на Go.

Ответ приходит в нижнее окно (Status). Вот как может выглядеть браузер Web-служб после обращения к Web-службе из примера.

Браузер Web-служб

Рис. 5. Браузер Web-служб

В окне Actions (действия) справа сверху есть ссылка на Source (источник). Щелчёк на Source показывает соответствующее SOAP-сообщение. Его можно изменить, а потом передать, щёлкнув на Go. Щёлкните на Form справа вверху, чтобы вернуть окно в начальное состояние. В окне статуса тоже есть ссылка на источник, позволяющая увидеть ответ SOAP. Если там говорится что отображать нечего (а ответ должен быть) - то наш код, скорее всего, не сработал.

После запуска Web-службы проверьте, есть ли сообщения об ошибках в серверной консоли или файле log.nsf. Мы можем делать отладку, включая в код сообщения MessageBox, которые отображаются на серверной консоли или в log.nsf. (Не используйте в Beta 2 выражений Print - они поступают в поток HTTP и искажают отклик SOAP.)

Дополнительные свойства

Во вкладке Advanced (Дополнительно) содержатся настройки, определяющие Web-службы и отражающиеся в документе WSDL.

Вкладка дополнительных настроек окна свойств Web-службы

Рис. 6. Вкладка дополнительных настроек окна свойств Web-службы

Мы можем указать имена для типа порта, элемента службы и порта службы. Например, можем указать все имена как GetSubject. Для большей ясности суффиксом служит тип элемента. Указанные имена вставляются в документ WSDL. При импорте документа имена в окно настроек берутся из него.

Ниже - полный документ WSDL из примера GetSubject. Отмечены те части, которые отражены в дополнительных настройках.

<?xml version="1.0"
      encoding="UTF-8"?> <wsdl:definitions
        targetNamespace="urn:DefaultNamespace"
        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">
 <wsdl:message name="getNthSubjectResponse">
  <wsdl:part name="getNthSubjectReturn" type=
     "xsd:string"/> (6)
 </wsdl:message>
 <wsdl:message name="getNthSubjectRequest">
 <wsdl:part name="dbname" type=
    "xsd:string"/> (6)
 <wsdl:part name="viewname" type=
    "xsd:string"/> (6)
 <wsdl:part name="n" type="xsd:int"
    /> (6)
</wsdl:message>
 <wsdl:portType name="GetSubjectPortType"> (1)
  <wsdl:operation name="getNthSubject"
        parameterOrder="dbname viewname n">
   <wsdl:input message="impl:getNthSubjectRequest"
                  name="getNthSubjectRequest"/>
   <wsdl:output message="impl:getNthSubjectResponse"
                   name="getNthSubjectResponse"/>
  </wsdl:operation>
 </wsdl:portType>
 <wsdl:binding name="GetSubjectPortSoapBinding"
               type="impl:GetSubjectPortType">
  <wsdlsoap:binding style="rpc" (4)
                transport="http://schemas.xmlsoap.org/soap/http"/>
  <wsdl:operation name="getNthSubject">
   <wsdlsoap:operation soapAction=""/> (7)
   <wsdl:input name="getNthSubjectRequest">
    <wsdlsoap:body
      encodingStyle="http://schemas.xmlsoap.org/soap/
         encoding/" (5)
      namespace="urn:DefaultNamespace" use=
         "encoded"/> (5)
  </wsdl:input>
   <wsdl:output name="getNthSubjectResponse">
    <wsdlsoap:body
      encodingStyle="http://schemas.xmlsoap.org/soap/encoding/
        " (5)
      namespace="urn:DefaultNamespace" use=
         "encoded"/> (5)
  </wsdl:output>
  </wsdl:operation>
 </wsdl:binding>
 <wsdl:service name="GetSubjectElement"> (2)
  <wsdl:port binding="impl:GetSubjectPortSoapBinding"
                name="GetSubjectPort"> (3)
   <wsdlsoap:address location="http://localhost"/>
  </wsdl:port>
 </wsdl:service>
</wsdl:definitions>

(1) Типом порта определяется набор операций. Атрибут wsdl:portType из документа WSDL соответствует параметру Port type name (имя типа порта) в дополнительных настройках.

(2) В службе определены поддерживаемые порты. Атрибут wsdlsoap:address в документе соответствует параметру Service element name (имя элемента службы) во вкладке с настройками. Если документ WSDL был получен через Export WSDL, Show WSDL или предварительный просмотр в Domino Designer, то атрибут location (местонахождение) параметра wsdlsoap:address содержит некорректные данные; они правильные в случае получения WSDL документа URL-командой ?WSDL.

(3) Портом указывается связь, которая в свою очередь определяет тип порта и даёт доступ к дополнительной информации. В документе WSDL внутри атрибута wsdl:service содержится атрибут с именем порта wsdl:port. В Domino может быть указана одна служба и в каждой службе - один порт.

(4) Можно выбрать из двух режимов программирования и четырёх форматов SOAP-сообщений. Режим программирования RPC допускает использование четырёх форматов SOAP-сообщений: RPC/шифрованные, RPC/символьные, Doc/символьные и Wrapped (скрытые) (пятый возможный формат, Doc/шифрованный, не до конца понят, а потому не используется здесь). В режиме программирования Message автоматически включается формат Doc/символьный, но это только в качестве намёка; реальный формат SOAP-сообщения, проходящего на работающую в режиме Message Web-службу, не публикуется, а устанавливается по личной договорённости между поставщиком и пользователем. Атрибут style (стиль) в wsdlsoap:binding устанавливается следующим образом:

  • wsdlsoap:binding style="rpc" для RPC/шифрованных и RPC/символьных
  • wsdlsoap:binding style="document" для Doc/символьных и скрытых

(5) В элементах input и output в wsdlsoap:binding элемент use wsdl:soap:body устанавливается следующим образом:

  • wsdlsoap:body use="encoded" for RPC/encoded. для RPC/шифрованных. В этом случае присутствует элемент encodingStyle.
  • " wsdlsoab:body use="literal" для RPC/символьных, Doc/символьных и скрытых. В этих случаях нет атрибута encodingStyle.

(6) В RPC/шифрованных и RPC/символьных в каждой части сообщения тип данных определяется прямой ссылкой на пространство имён XMLSchema (например, type="xsd:string" или type="xsd:int") или комплексный тип, определённый в секции "types" документа WSDL (в примере этого нет).

В Doc/символьных каждая часть сообщения относится к ранее определённому элементу данных. Ниже приведён пример из документа WSDL с указанным Doc/символьным форматом. В wsdl:types каждая вводимая часть определена в элементе, указанном после соответствующего параметра процедурного кода и выводимая часть определена в элементе, указанном после процедуры и Return.

<wsdl:types>
  <schema targetNamespace="urn:DefaultNamespace"
          xmlns="http://www.w3.org/2001/XMLSchema">
   <element name="dbname" type="xsd:string"/>
   <element name="viewname" type="xsd:string"/>
   <element name="n" type="xsd:int"/>
   <element name="getNthSubjectReturn" type="xsd:string"/>
  </schema>
</wsdl:types>
<wsdl:message name="getNthSubjectResponse">
  <wsdl:part element="impl:getNthSubjectReturn"
             name="getNthSubjectReturn"/>
</wsdl:message>
<wsdl:message name="getNthSubjectRequest">
  <wsdl:part element="impl:dbname" name="dbname"/>
  <wsdl:part element="impl:viewname" name="viewname"/>
  <wsdl:part element="impl:n" name="n"/>
</wsdl:message>

ЧТобы быть закрытой, для каждого сообщения одна часть , названная в соответствии с использующей её операцией и не имеющая, относится к предварительно определённому элементу типа complexType. Ниже приведён отрывок кода WSDL в скрытом формате.

<wsdl:types>
  <schema targetNamespace="urn:DefaultNamespace"
          xmlns="http://www.w3.org/2001/XMLSchema">
   <element name="getNthSubject">
    <complexType>
     <sequence>
      <element name="dbname" type="xsd:string"/>
      <element name="viewname" type="xsd:string"/>
      <element name="n" type="xsd:int"/>
     </sequence>
    </complexType>
   </element>
   <element name="getNthSubjectResponse">
    <complexType>
     <sequence>
      <element name="getNthSubjectReturn" type="xsd:string"/>
     </sequence>
    </complexType>
   </element>
  </schema>
</wsdl:types>
<wsdl:message name="getNthSubjectResponse">
  <wsdl:part element="impl:getNthSubjectResponse" name="parameters"/>
</wsdl:message>
<wsdl:message name="getNthSubjectRequest">
  <wsdl:part element="impl:getNthSubject" name="parameters"/>
</wsdl:message>

Великолепное рассмотрение форматов SOAP вы можете найти в статье developerWorks "Какой стиль WSDL мне использовать?" автор Расселл Батек (Russell Butek).

(7) параметр soapAction ="" если не стоит галочка на "Включить имя операции в действие SOAP". Если этот параметр отмечен, то в soapAction указывается имя операции, например:

<wsdlsoap:operation soapAction="getNthSubject"/>

Безопасность

Настройки безопасности Web-служб аналогичны запрашиваемым через интернет серверным агентам. Ниже приведён пример вкладки безопасность (security) окна настроек Web-служб.

Вкладка безопасности окна свойств Web-службы

Рис. 7. Вкладка безопасности окна свойств Web-службы

Первыми двумя строчками определяется, кто является фактическим пользователем Web-службы. Если они не заполнены, то фактическим пользователем является хозяин Web-службы (последний пользователь, редактировавший её элементы).

  • Если отмечено "Run as web user", то фактическим пользователем становится тот, кто имеет сетевой доступ к базе данных, содержащей Web-службу: Anonymous в базах данных, допускающих анонимный доступ, или с получаемым при аутентификации именем.
  • Если заполнено поле "Run on behalf of", то это и есть фактический пользователь.

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

"Компилировать код Java с отладочной информацией" допускает подсоединение к Web-службе отладчика Java, вроде поддерживающего JPDA (Отладочную архитектуру для Java-платформ) Eclipse. Java-отладка появилась тольков версии 7 и работает исключительно с клиентом Notes. То есть, для отладки Web-служба должна быть размещена на клиенте Notes. Запустите процесс HTTP на клиенте, выбрав в браузере Design - Preview. Вызовите Web-службу. В Web-службе должен содержаться код только для отладки, который приостанавливает работу службы на какое-то время. После этого подключайте отладчик к работающей Web-службе.

В Web-службах на LotusScript вместо отладочной строки Java есть опция "Допускать удалённую отладку". Удалённая отладка у Web-служб такая же, как и у агентов. В этом случае Web-служба должна находиться на сервере.

Опцией "Собрать информацию по Web-службе" включается сбор затраченных Domino Objects отрезков времени. Просмотреть результаты выбранной Web-службы можно, выбрав Design-View Profile Results. Сбор информации новый в 7-ой версии и работает как с Web-службами, так и с написанными на LotusScript или Java агентами.

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

Опцией "Доступ к службе по умолчанию" мы можем разрешить использование службы всем, или перечислить разрешённых пользователей.

Контекстная среда Web-служб

Строение Web-служб такое же, как и у агентов. С другой стороны, большинство контекста агентов, однако не весь, применимо к Web-службам. Мы уже видели, как получить объекты Session и AgentContext в Java и NotesSession в LotusScript. Вот остальные основные контекстные элементы, применимые к Web-службам:

Contextual element 

Java 

LotusScript 

Текущая Web-служба AgentContext.getCurrentAgent(); NotesSession.CurrentAgent
Текущая база данных AgentContext.getCurrentDatabase(); NotesSession.CurrentDatabase
Вывод на серверную консоль и log.nsf System.out Messagebox
Имя и псевдоним Web-службы Agent.getName(); NotesAgent.Name
Хозяин Web-службы (полное имя) Agent.getOwner(); NotesAgent.Owner
Хозяин Web-службы (внутреннее имя) Agent.getCommonOwner(); NotesAgent.CommonOwner
Хозяин Web-службы в настоящий момент Agent.getOnBehalfOf(); NotesAgent.OnBehalfOf
Комментарий к Web-службе Agent.getComment(); NotesAgent.Comment
HTTP URL Web-службы Agent.getHttpURL(); NotesAgent.HttpURL
Notes URL Web-службы Agent.getNotesURL(); NotesAgent.NotesURL
Родительская бд Web-службы Agent.getParent(); NotesAgent.Parent
Держатели шлюзов Web-службы Agent.getLockHolders(); NotesAgent.LockHolders

Элементы Web-службы могут быть закрыты и открыты так же, как и агенты.

Здесь приведён пример LotusScript, демонстрирующий получение свойств, связанных с контекстом Web-службы. В Web-службе 3 операции.

Option Public
%INCLUDE "lsxsd.lss"
Dim s As NotesSession
Dim agent As NotesAgent

Class GetAgentContext

  Sub NEW
    Set s = New NotesSession
    Set agent = s.CurrentAgent
  End Sub

  Function getAgentName() As String
    getAgentName = agent.Name
  End Function

  Function getEffectiveUserName() As String
    getEffectiveUserName = s.EffectiveUserName
  End Function

  Function getDatabaseFileName() As String
    Dim db As NotesDatabase
    Set db = s.CurrentDatabase
    getDatabaseFileName = db.FileName
  End Function

End Class

Ниже приведён код Java.

import lotus.domino.*;
import lotus.domino.types.*;

public class GetAgentContext {

  Session s;
  AgentContext ac;

  public GetAgentContext() {
    s = WebServiceBase.getCurrentSession();
    try {
      ac = s.getAgentContext();
    } catch(Exception e) {
      e.printStackTrace(); }
  }

  public java.lang.String getAgentName() {
    String agentName = null;
    try {
      Agent agent = ac.getCurrentAgent();
      agentName = agent.getName();  }
    catch(Exception e) {
      e.printStackTrace(); }
    return agentName;
  }

  public java.lang.String getEffectiveUserName() {
    String userName = null;
    try {
      userName = ac.getEffectiveUserName();  }
    catch(Exception e) {
      e.printStackTrace(); }
    return userName;
  }

  public java.lang.String getCurrentDatabase() {
    String dbFileName = null;
    try {
      Database db = ac.getCurrentDatabase();
      dbFileName = db.getFileName();  }
    catch(Exception e) {
      e.printStackTrace(); }
    return dbFileName;
  }
}

Сложные типы данных

Операции, работающие по следующей модели, не нуждаются в сложных типах данных:

  • Простое скалярное возвращаемое значение на выходе (или вообще ничего не возвращается);
  • Скалярные входные параметры (или вообще без них);

Операции, возвращающие более одного скалярного значения, или требующие более чем скалярные значения на входе, нуждаются в сложных типах данных. Использование сложных типов данных позволяет перемещать большие и разнородные структуры данных.

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

  • Массивы
  • Классы
  • Входяще-возвращаемые и возвращаемые параметры.

Массивы
Массивы отображаются в элемент WSDL complexType и называются ArrayOf с суффиксом, обозначающим тип данных. Элемент complexType в WSDL определён как массив.

Например, выполненная на Java операция из примера возвращает массив из строк.

public java.lang.String[] getAll() {
  String[] info = new String[3];
  try {
    info[0] = ac.getEffectiveUserName();
    info[1] = s.getPlatform();
    info[2] = s.getNotesVersion(); }
  catch(Exception e) {
    e.printStackTrace(); }
  return info;
}

Массив типа String в Java соответствует определённому как массив из строк элементу complexType WSDL ArrayOf_xsd_string. В определяющем возвращаемое значение операции getAll(getAllResponse) сообщении указана одна часть типа ArrayOf_xsd_string.

- <wsdl:types>
  - <schema targetNamespace="urn:DefaultNamespace"
      xmlns="http://www.w3.org/2001/XMLSchema">
      <import namespace="http://schemas.xmlsoap.org/soap/encoding/" />
    - <complexType name="ArrayOf_xsd_string">
      - <complexContent>
        - <restriction base="soapenc:Array">
            <attribute ref="soapenc:arrayType"
              wsdl:arrayType="xsd:string[]" />
          </restriction>
        </complexContent>
      </complexType>
    </schema>
  </wsdl:types>
- <wsdl:message name="getAllResponse">
    <wsdl:part name="getAllReturn" type="impl:ArrayOf_xsd_string" />
  </wsdl:message>

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

Option Public
%INCLUDE "lsxsd.lss"
Dim s As NotesSession

Class infoArray
  Public info() As String
End Class

Class GetSessionInfo
  Sub NEW
    Set s = New NotesSession
  End Sub

  Function getItAll() As infoArray
    Set getItAll = New infoArray
    Redim getItAll.info(1 To 3)
    getItAll.info(1) = s.EffectiveUserName
    getItAll.info(2) = s.Platform
    getItAll.info(3) = s.NotesVersion
  End Function
End Class

Классы
Классы соответствуют элементу WSDL complexType, названному в соответствии с названием класса. Далее следует пример на языке Java, возвращающий тот же результат, но уже в качестве объекта, а не массива.

public InfoClass getAll2() {
  InfoClass info = new InfoClass();
  try {
    info.effectiveUserName = ac.getEffectiveUserName();
    info.platform = s.getPlatform();
    info.notesVersion = s.getNotesVersion(); }
  catch(Exception e) {
    e.printStackTrace(); }
  return info;
}

public class InfoClass {
  public String effectiveUserName;
  public String platform;
  public String notesVersion;
}

Класс InfoClass в Java соответствует элементу complexType с таким же названием. ComplexType содержит три элемента типа xsd:string с такими же названиями, как и у публичных элементов данных в классе InfoClass в Java.

- <wsdl:types>
  - <schema targetNamespace="urn:DefaultNamespace"
      xmlns="http://www.w3.org/2001/XMLSchema">
      <import namespace="http://schemas.xmlsoap.org/soap/encoding/" />
    - <complexType name="InfoClass">
      - <sequence>
          <element name="notesVersion"
            nillable="true" type="xsd:string" />
          <element name="platform"
            nillable="true" type="xsd:string" />
          <element name="effectiveUserName"
            nillable="true" type="xsd:string" />
        </sequence>
      </complexType>
    </schema>
  </wsdl:types>
- <wsdl:message name="getAll2Response">
    <wsdl:part name="getAll2Return" type="impl:InfoClass" />
  </wsdl:message>

А вот эквивалент на LotusScript:

Option Public
%INCLUDE "lsxsd.lss"
Dim s As NotesSession

Class InfoClass
  Public EffectiveUserName As String
  Public Platform As String
  Public NotesVersion As String
End Class

Class GetSessionInfo
  Sub NEW
    Set s = New NotesSession
  End Sub

  Function getItAll2() As InfoClass
    Set getItAll2 = New InfoClass
    getItAll2.EffectiveUserName = s.EffectiveUserName
    getItAll2.Platform = s.Platform
    getItAll2.NotesVersion = s.NotesVersion
  End Function
End Class

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

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

Здесь WSDL из первого примера возвращает данные во входящих параметрах:

- <wsdl:message name="getNthSubjectResponse">
    <wsdl:part name="getNthSubjectReturn" type="xsd:string" /> (1)
    <wsdl:part name="dbname" type="xsd:string" /> (2)
    <wsdl:part name="viewname" type="xsd:string" /> (3)
    <wsdl:part name="n" type="xsd:int" /> (4)
  </wsdl:message>
- <wsdl:message name="getNthSubjectRequest">
    <wsdl:part name="dbname" type="xsd:string" /> (2)
    <wsdl:part name="viewname" type="xsd:string" /> (3)
    <wsdl:part name="n" type="xsd:int" /> (4)
  </wsdl:message>

(1)Одно из возвращаемых значений, getNthSubjectReturn, не совпадает ни с одним из параметров. Это значение возвращается как значение метода или функции. Остальные три возвращаемые части. (2) (3) (4) ), dbname, viewname и n соответствуют параметрам. Они становятся тремя входяще-возвращаемыми параметрами.

Входяще/возвращаемые и возвращаемые параметры могут принадлежать к простым типам данных. В стандартном Java есть содержащий методы для использования входяще-возвращаемых и возвращаемых параметров различных типов пакет javax.xml.rpc.holders. В Lotus Domino входяще-возвращаемые и возвращаемые параметры соответствуют нижеуказанным классам.

BigDecimalHolder CalendarHolder LongHolder
BigIntegerHolder DoubleHolder LongWrapperHolder
BooleanHolder DoubleWrapperHolder ObjectHolder
BooleanWrapperHolder FloatHolder QNameHolder
ByteArrayHolder FloatWrapperHolder ShortHolder
ByteHolder IntegerWrapperHolder ShortWrapperHolder
ByteWrapperHolder IntHolder StringHolder

В этих классах содержится публичная переменная value (значение), которую можно получить и поменять методами класса. В следующем примере представлен вариант операции getNthSubject; как и раньше, она возвращает объект типа String, однако теперь, благодаря использованию классов StringHolder и IntHolder три параметра становятся входяще-возвращаемыми. Значения параметров возвращаются пользователю в ответном сообщении SOAP.

import lotus.domino.*;
import lotus.domino.types.*;

public class GetSubject {

  Session s;

  public GetSubject() {
    s = WebServiceBase.getCurrentSession();
  }

  public String getNthSubject(javax.xml.rpc.holders.StringHolder dbname,
      javax.xml.rpc.holders.StringHolder viewname,
      javax.xml.rpc.holders.IntHolder n) {
    String subject = null;
    try {
      Database db = s.getDatabase(null, dbname.value);
      if (!db.isOpen()) subject = "Cannot open database " + dbname.value;
      else {
        View view = db.getView(viewname.value);
        if (view == null) subject = "Cannot open view " + viewname.value;
        else {
          Document doc = view.getNthDocument(n.value);
          if (doc == null) subject = "Cannot get document " + n.value;
          else {
            if (doc.hasItem("Subject"))
              subject = doc.getItemValueString("Subject");
            else subject = "Document does not have Subject";
          }
        }
      }
    }
    catch(Exception e) {
      e.printStackTrace();
    }

    return subject;
  }
}

В LotusScript во включаемом файле lsxsd.lss определены классы-держатели для входяще-возвращаемых и возвращаемых параметров.

BOOLEAN_HOLDER LONG_HOLDER
BOOLEANARRAY_HOLDER LONGARRAY_HOLDER
BYTE_HOLDER SINGLE_HOLDER
BYTEARRAY_HOLDER SINGLEARRAY_HOLDER
DOUBLE_HOLDER STRING_HOLDER
DOUBLEARRAY_HOLDER STRINGARRAY_HOLDER
INTEGER_HOLDER VARIANT_HOLDER
INTEGERARRAY_HOLDER VARIANTARRAY_HOLDER

В этих классах содержится публичная переменная value (значение), которую можно получить и поменять методами класса. Следующий пример на LotusScript делает то же, что и предыдущий на Java. Для трёх входяще-возвращаемых параметров использованы классы-держатели.

Option Public
%INCLUDE "lsxsd.lss"

Dim s As NotesSession

Class GetSubject

  Sub NEW
    Set s = New NotesSession
  End Sub

  Function getNthSubject(dbname As String_Holder, _
  viewname As String_Holder, _
  n As Long_Holder) As String
    Dim db As NotesDatabase
    Dim view As NotesView
    Dim doc As NotesDocument
    Set db = s.GetDatabase("", dbname.Value)
    If Not(db.IsOpen) Then
      getNthSubject = "Cannot open database " & _
          dbname.Value
      Exit Function
    End If

    Set view = db.GetView(viewname.Value)
    If view Is Nothing Then
      getNthSubject = "Cannot open view " & _
           viewname.Value
      Exit Function
    End If

    Set doc = view.GetNthDocument(n.Value)
    If doc Is Nothing Then
      getNthSubject = "Cannot get document " & _
          n.Value
      Exit Function
    End If
    If doc.HasItem("Subject") Then
      getNthSubject = doc.GetItemValue("Subject")(0)
    Else
      getNthSubject = "Document does not have Subject"
    End If
  End Function

End Class

Преобразование типов данных

Простые типы данных и их аналоги в XSD обычно соответствуют друг другу. За исключением импортированным типам данных SOAPENC, которые преобразуются в объекты. Однако при генерации WSDL объект преобразуется в тип данных XSD.

Проимпортированный WSDL   Тип данных в Java
Тип данных в LotusScript
 
Сгенерированный WSDL  
xsd:boolean boolean
Boolean
xsd:boolean
soapenc:boolean java.lang.Boolean
XSD_BOOLEAN (1) 
xsd:boolean
xsd:byte byte
XSD_BYTE (2) 
xsd:byte
soapenc:byte java.lang.Byte
XSD_BYTE
xsd:byte
xsd:double double
Double
xsd:double
soapenc:double java.lang.Double
XSD_DOUBLE
xsd:double
xsd:float float
Single
xsd:float
soapenc:float java.lang.Float
XSD_FLOAT
xsd:float
xsd:int int
Long
xsd:int
soapenc:int java.lang.Integer
XSD_INT
xsd:int
xsd:long long
XSD_LONG (3)  
xsd:long
soapenc:long java.lang.Long
XSD_LONG
xsd:long
xsd:short short
Integer
xsd:short
soapenc:short java.lang.Short
XSD_SHORT
xsd:short
xsd:string java.lang.String (4)
String
xsd:string
soapenc:string java.lang.String
XSD_STRING
xsd:string

(1) В Java используются свёрнутые классы, которые определены в java.lang: java.lang.Boolean, java.lang.Byte и т.п. В LotusScript используются определённые в lsxsd.lss классы XSD_: XSD_BOOLEAN, XSD_BYTE и т.п. Классы в LotusScript наследуют следующие методы:

Function GetValueAsString() As String
Sub SetValueAsString(value As String)

Примечание: В ожидаемом релизе Beta название SetValueAsString будет изменено на SetValueFromString.

Ниже приведён пример операции на Java, возвращаемое значение которой относится к типу java.lang.Boolean.

import lotus.domino.*;
import lotus.domino.types.*;

public class GetDatabaseInfo {

  Session s;
  AgentContext ac;
  Database db;

  public GetDatabaseInfo() {
    s = WebServiceBase.getCurrentSession();
    try {
      ac = s.getAgentContext();
      db = ac.getCurrentDatabase();
    } catch(Exception e) {
      e.printStackTrace(); }
  }

  public Boolean doesViewExist(String viewName) {
    Boolean b = null;
    try {
      if (db.getView(viewName) == null)
        b = new Boolean(false);
      else
        b = new Boolean(true);
    } catch(Exception e) {
      e.printStackTrace(); }
    return b;
  }
}

Соответствующая операция на LotusScript, возвращающая значение типа XSD_BOOLEAN:

Option Public
%INCLUDE "lsxsd.lss"
Dim s As NotesSession
Dim db As NotesDatabase

Class GetDatabaseInfo

  Sub NEW
    Set s = New NotesSession
    Set db = s.CurrentDatabase
  End Sub

  Function DoesViewExist(viewName As String) As XSD_BOOLEAN
    Set b = New XSD_BOOLEAN
    If db.GetView(viewName) Is Nothing Then
      Call b.SetValueAsString("False")
    Else
      Call b.SetValueAsString("True")
    End If
    Set DoesViewExist = b
  End Function

End Class

(2) В LotusScript для xsd:byte не используется простой тип. Он всегда преобразуется в XSD_BYTE (простой тип в LotusScript преобразуется в xsd:unsignedByte). (3) Также в LotusScript для xsd:long не используется простой тип. Он всегда преобразуется в XSD_LONG (простой тип в LotusScript соответствует xsd:int. (4) В Java нет простого типа для xsd:string. Он всегда преобразуется в java.lang.String.

Прочие типы данных XSD соответствуют объектам из java.lang, java.math, java.util и lotus.domino.types (новое в Lotus Notes/Domino 7) в Java и XSD_OBJECTS в LotusScript.

WSDL  Тип данных Java
Тип данных LotusScript
 
xsd:anyType java.lang.Object
XSD_ANYTYPE
Variant (1) 
xsd:anyURI lotus.domino.types.URI
XSD_ANYURI
xsd:base64Binary
soapenc:base64 (2) 
byte[]
xsd:date java.util.Date
XSD_DATE
xsd:dateTime java.util.Calendar
XSD_DATETIME
xsd:decimal
soapenc:decimal (3) 
java.math.BigDecimal
XSD_DECIMAL
xsd:duration lotus.domino.types.Duration
XSD_DURATION
xsd:ENTITY lotus.domino.types.Entity
XSD_ENTITY
xsd:ENTITES lotus.domino.types.Entities
XSD_ENTITIES
xsd:gDay lotus.domino.types.GDay
XSD_GDAY
xsd:gMonth lotus.domino.types.GMonth
XSD_GMONTH
xsd:gMonthDay lotus.domino.types.GMonthDay
XSD_GMONTHDAY
xsd:gYear lotus.domino.types.GYear
XSD_GYEAR
xsd:gYearMonth lotus.domino.types.GYearMonth
XSD_GYEARMONTH
xsd:hexBinary lotus.domino.types.HexBinary
XSD_HEXBINARY
xsd:ID lotus.domino.types.Id
XSD_ID
xsd:IDREF lotus.domino.types.IDRef
XSD_IDREF
xsd:IDREFS lotus.domino.types.IDRefs
XSD_IDREFS
xsd:integer
soapenc:integer (3) 
java.math.BigInteger
XSD_INTEGER
xsd:language lotus.domino.types.Language
XSD_LANGUAGE
xsd:Name lotus.domino.types.Name
XSD_NAME
xsd:NCName lotus.domino.types.NCName
XSD_NCNAME
xsd:negativeInteger lotus.domino.types.NegativeInteger
XSD_NEGATIVEINTEGER
xsd:NMTOKEN lotus.domino.types.NMToken
XSD_NMTOKEN
xsd:NMTOKENS lotus.domino.types.NMTokens
XSD_NMTOKENS
xsd:nonNegativeInteger lotus.domino.types.NonNegativeInteger
XSD_NONNEGATIVEINTEGER
xsd:nonPositiveInteger lotus.domino.types.NonPositiveInteger
XSD_NONPOSITIVEINTEGER
xsd:NOTATION lotus.domino.types.Notation
XSD_NOTATION
xsd:normalizedString lotus.domino.types.NormalizedString
XSD_NORMALIZEDSTRING
xsd:positiveInteger lotus.domino.types.PositiveInteger
XSD_NONPOSITIVEINTEGER
xsd:QName javax.xml.namespace.QName
XSD_QNAME
xsd:time lotus.domino.types.Time
XSD_TIME
xsd:token lotus.domino.types.Token
XSD_TOKEN
xsd:unsignedByte lotus.domino.types.UnsignedByte
Byte
XSD_UNSIGNEDBYTE (4) 
xsd:unsignedInt lotus.domino.types.UnsignedInt
XSD_UNSIGNEDINT
xsd:unsignedLong lotus.domino.types.UnsignedLong
XSD_UNSIGNEDLONG
xsd:unsignedShort lotus.domino.types.UnsignedShort
XSD_UNSIGNEDSHORT

(1) Тип Variant при генерации WSDL преобразуется в xsd:anyType. (2) При импортировании из WSDL soapenc:base64 преобразуется в byte[] и Byte. В сгенерированном WSDL всегда преобразуется в xsd:base64Binary. (3) soapenc:decimal и soapenc:integer при импорте из WSDL преобразуются в XSD:DECIMAL и XSD:INTEGER. В сгенерированном WSDL всегда преобразуются в xsd:decimal и xsd:integer. (4) xsd:unsignedByte при импорте из WSDL преобразуется в Byte. В сгенерированном WSDL и Byte, и XSD_UNSIGNEDBYTE преобразуются в xsd:unsignedByte.

Собственные процедуры

В Web-службах Domino отображаются публичные процедуры, методы и подпрограммы исполняемой части класса. Собственные процедуры спрятаны. Ниже приведён пример GetSubject, в котором операции getFirstSubject, getLastSubject и getNthSubject отображаются в качестве публичных процедур. Выполняемый код содержится в собственных процедурах openDatabase, openView и getSubject.

Dim s As NotesSession
Dim db As NotesDatabase
Dim view As NotesView
Dim doc As NotesDocument
Dim msg As String

Class GetSubject

  Sub NEW
    Set s = New NotesSession
  End Sub

  Function getFirstSubject(dbname As String, viewname As String) As String
    If openDatabase(dbname) Then
      If openView(viewname) Then
        Set doc = view.GetFirstDocument
        If doc Is Nothing Then
          msg = "Cannot get first document "
        Else
          Call getSubject
        End If
      End If
    End If
    getFirstSubject = msg
  End Function

 Function getLastSubject(dbname As String, viewname As String) As String
    If openDatabase(dbname) Then
      If openView(viewname) Then
        Set doc = view.GetLastDocument
        If doc Is Nothing Then
          msg = "Cannot get last document "
        Else
          Call getSubject
        End If
      End If
    End If
    getLastSubject = msg
  End Function

  Function getNthSubject(dbname As String, viewname As String, n As Integer) As String
    If openDatabase(dbname) Then
      If openView(viewname) Then
        Set doc = view.GetNthDocument(n)
        If doc Is Nothing Then
          msg = "Cannot get document " & n
        Else
          Call getSubject
        End If
      End If
    End If
    getNthSubject = msg
  End Function

  Private  Function openDatabase(dbname As String) As Boolean
    Set db = s.GetDatabase("", dbname)
    If db.IsOpen Then
      openDatabase = True
    Else
      openDatabase = False
      msg = "Cannot open database " & dbname
    End If
  End Function

  Private Function openView(viewname As String) As Boolean
    Set view = db.GetView(viewname)
    If view Is Nothing Then
      openView = False
      msg = "Cannot open view " & viewname
    Else
      openView = True
    End If
  End Function

  Private Sub getSubject
    If doc.HasItem("Subject") Then
      msg = doc.GetItemValue("Subject")(0)
    Else
      msg = "Document does not have Subject"
    End If
  End Sub

End Class

А вот пример на Java:

import lotus.domino.*;
import lotus.domino.types.*;

public class GetSubject {

  Session s;
  Database db;
  View view;
  Document doc;
  String msg;

  public GetSubject() {
    s = WebServiceBase.getCurrentSession();
  }

  public String getFirstSubject(String dbname, String viewname) {
    try {
      if (openDatabase(dbname)) {
        if (openView(viewname)) {
          doc = view.getFirstDocument();
          if (doc == null)
            msg = "Cannot get first document ";
          else
            getSubject();
        }
      }
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    return msg;
  }

  public String getLastSubject(String dbname, String viewname) {
    try {
      if (openDatabase(dbname)) {
        if (openView(viewname)) {
          doc = view.getLastDocument();
          if (doc == null)
            msg = "Cannot get last document ";
          else
            getSubject();
        }
      }
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    return msg;
  }

  public String getNthSubject(String dbname, String viewname, int n) {
    try {
      if (openDatabase(dbname)) {
        if (openView(viewname)) {
          doc = view.getNthDocument(n);
          if (doc == null)
            msg = "Cannot get document " + n;
          else
            getSubject();
        }
      }
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    return msg;
  }

  private boolean openDatabase(String dbname) {
    boolean b = false;
    try {
      db = s.getDatabase(null, dbname);
      if (db.isOpen())
        b = true;
      else
        msg = "Cannot open database " + dbname;
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    return b;
  }

  private boolean openView(String viewname) {
    boolean b = false;
    try {
      view = db.getView(viewname);
      if (view != null)
        b = true;
      else
        msg = "Cannot open view " + viewname;
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    return b;
  }

  private void getSubject() {
    try {
      if (doc.hasItem("Subject"))
        msg = doc.getItemValueString("Subject");
      else
        msg = "Document does not have Subject";
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

}

Заключение

Lotus Notes/Domino 7 - инструмент для поставщика Web-служб, позволяющий работать с ними через элементы управления, аналогичные агентным. Web-служба должна находиться на сервере Domino 7 с открытым HTTP-доступом, за исключением того, что проверить работоспособность и провести отладку Web-службы можно через предварительный интернет-просмотр в клиенте Notes. Пользователи используют Web-службы Domino через SOAP-кодированные запросы HTTP POST.

Операции Web-служб преобразуются в публичные методы Java и публичные функции и подпрограммы LotusScript. Элементы данных Web-служб преобразуются в параметры и возвращаемые значения. Когда это возможно, типы данных XSD преобразуются в простые типы данных Java и LotusScript. Элементы сложных типов преобразуются в объекты.

В статье описано Lotus Notes/Domino 7 версии Beta 2. В процессе дальнейшей разработки могут быть внесены некоторые усовершенствования. Например, в следующей версии ожидается поддержка размещения кода Web-служб в библиотеках скриптов.


Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=2412