Опубликован: 04.07.2008 | Уровень: профессионал | Доступ: платный | ВУЗ: Компания IBM
Лекция 3:

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

< Лекция 2 || Лекция 3: 12345 || Лекция 4 >

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, выполните следующее:

  1. Откройте базу данных ITSO Web Services в Domino Designer, затем выберите Shared Code => Web Services.
  2. Щелкните по кнопке Import WSDL и выберите файл WSDL, который хотите импортировать. В нашем сценарии мы импортировали файл, который экспортировали в предыдущем разделе (см. рис. 3.14).
    Импортирование документа WSDL

    увеличить изображение
    Рис. 3.14. Импортирование документа WSDL
  3. В результате импортирования документа WSDL будет сгенерирован каркасный код, который в нашем сценарии сгенерирован на языке LotusScript, как показано в примере 3.11. Затем мы открыли окно свойств Web Service, поставили галочку рядом с опцией Warn if the WSDL interface is modified ( рис. 3.15).
    Импортирование документа WSDL: окно свойств Web Service

    увеличить изображение
    Рис. 3.15. Импортирование документа WSDL: окно свойств Web Service
    %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.11. Каркасный код, сгенерированный после импортирования документа WSDL

3.9 Работа с исключениями и ошибками в Web-сервисах

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

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

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

Для получения дополнительной информации о том, как работать с ошибками, используя язык LotusScript см. "Улучшение работы приложения фирмы ITSO Electronics с помощью Web-сервисов" , "Использование 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 решила применить программный продукт с открытым исходным кодом Apache SOAP, чтобы использовать Web-сервисы с помощью Java. Apache SOAP представляет собой реализацию стандарта SOAP в W3C. Он заменяет собой разработку IBM SOAP4J. Последующий, улучшенный проект Apache Axis доступен по следующему адресу: http://ws.apache.org/axis/

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

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

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

  1. Загрузите самую последнюю версию Apache SOAP по следующей ссылке: http://ws.apache.org/soap/
  2. Извлеките загруженный файл во временную директорию, в нашем сценарии в качестве такой папки мы использовали папку c:\soap.
  3. Экспортируйте сложный Web-сервис ProductService (находящийся в базе данных Web Services) в документ WSDL. В экспортированном документе WSDL содержится вся информация, необходимая для использования Web-сервиса.
  4. Откройте документ 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>
    Пример 3.12. Тип WSDL для Product
  5. Откройте новую базу данных WS Consumer в Domino Designer, выберите Shared Code => Agents (Общий код \Rightarrow Агенты), после чего щелкните по кнопке New agent (Создать агент).
  6. В поле Name окна свойств Agent введите ConsumeWS и в разделе Runtime в выпадающем меню Target (Цель) выберите None (Отсутствует), как показано на рис. 3.16.
    Окно свойств ConsumerWS Agent

    Рис. 3.16. Окно свойств ConsumerWS Agent
  7. Закройте окно свойств Agent, затем выберите язык кода Java.
  8. Нам необходимо создать класс JavaBean, представляющий сложный тип данных Product, определенный в документе WSDL. Для облегчения этой операции мы воспользуемся возможностью импортирования WSDL для автоматической генерации класса JavaBean. После этого нам необходимо выбрать Shared Code => Web Service (Общий код \Rightarrow Web-сервис) и щелкнуть по кнопке New Web Service (Создать Web-сервис).
  9. Закройте окно свойств Web Service и убедитесь в том, что язык описания Web-сервиса установлен на Java. Щелкните по кнопке Import WSDL (Импортировать WSDL), затем выберите созданный ранее документ WSDL. В результате импортирования этого документа будут автоматически созданы классы JavaBeansTM.
  10. Выделите и скопируйте код Java для Product.java.
  11. Вернитесь к агенту и щелкните по кнопке New Class (Создать класс). Затем замените класс Untitled.java скопированным кодом Product.java, так же, как это сделано в примере 3.13.
  12. Сохраните агент ConsumeWS и убедитесь в том, что он был успешно скомпилирован.

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

    Окно Organize Java Agent Files

    увеличить изображение
    Рис. 3.17. Окно Organize Java Agent Files
  13. Вам необходимо код JavaAgent.java по умолчанию заменить своим собственным, чтобы приступить к использованию Web-сервиса, который в нашем сценарии представлен в примере 3.14. Убедитесь в том, что в классе JavaAgent.java есть переменные URL и soapAction. Эти переменные должны указывать на расположение вашего приложения.
  14. Сохраните агент ConsumeWS.
  15. Вернитесь к новому Web-сервису и закройте его без сохранения.
  16. Откройте клиент Lotus Notes и выберите базу данных WS Consumer. Перейдите к Actions => ConsumeWS (Действия \Rightarrow ConsumeWS) для того, чтобы запустить только что созданный агент. Агент отобразит набор объектов Product, используемых в Web-сервисе, в окне Java, как видно на рис. 3.18.
    Окно Java, в котором отображен результат работы Web-сервиса

    Рис. 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;
}
}
Пример 3.13. Код класса Product
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.14. Код, необходимый для использования Web-сервиса с помощью Java
< Лекция 2 || Лекция 3: 12345 || Лекция 4 >
Артем Поммер
Артем Поммер
Россия, Омск
Артур Гибадуллин
Артур Гибадуллин
Россия, Нижневартовск, ФГБОУ ВО НВГУ, Преподаватель