| Россия, Омск |
Улучшение работы приложения фирмы ITSO Electronics с помощью Web-сервисов
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.
- Щелкните по кнопке Import WSDL и выберите файл WSDL, который хотите импортировать. В нашем сценарии мы импортировали файл, который экспортировали в предыдущем разделе (см. рис. 3.14).
- В результате импортирования документа WSDL будет сгенерирован каркасный код, который в нашем сценарии сгенерирован на языке LotusScript, как показано в примере 3.11. Затем мы открыли окно свойств Web Service, поставили галочку рядом с опцией Warn if the WSDL interface is modified (
рис.
3.15).
%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).
Ошибки для метода описания сервиса на языке 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-сервис.
- Загрузите самую последнюю версию 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>Пример 3.12. Тип WSDL для Product - Откройте новую базу данных WS Consumer в Domino Designer, выберите Shared Code => Agents (Общий код
Агенты), после чего щелкните по кнопке New agent (Создать агент). - В поле Name окна свойств Agent введите ConsumeWS и в разделе Runtime в выпадающем меню Target (Цель) выберите None (Отсутствует), как показано на рис. 3.16.
- Закройте окно свойств Agent, затем выберите язык кода Java.
- Нам необходимо создать класс JavaBean, представляющий сложный тип данных Product, определенный в документе WSDL. Для облегчения этой операции мы воспользуемся возможностью импортирования WSDL для автоматической генерации класса JavaBean. После этого нам необходимо выбрать Shared Code => Web Service (Общий код
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 и убедитесь в том, что он был успешно скомпилирован.
Щелкните по кнопке Edit Project (Изменить проект), откроется окно Java Agent Files (см. рис. 3.17). Перейдите к нужной директории библиотеки SOAP LIB, в нашем случае эта директория находилась по следующему пути: c:\soap\soap-2_3_1\lib. В качестве типа файла выберите Archive (Архивный), щелкните по кнопке Add/Replace File(s) (Добавить/Заменить файлы), далее нажмите ОК.
- Вам необходимо код JavaAgent.java по умолчанию заменить своим собственным, чтобы приступить к использованию Web-сервиса, который в нашем сценарии представлен в примере 3.14. Убедитесь в том, что в классе JavaAgent.java есть переменные URL и soapAction. Эти переменные должны указывать на расположение вашего приложения.
- Сохраните агент ConsumeWS.
- Вернитесь к новому Web-сервису и закройте его без сохранения.
- Откройте клиент Lotus Notes и выберите базу данных WS Consumer. Перейдите к Actions => ConsumeWS (Действия
ConsumeWS) для того, чтобы запустить только что созданный агент. Агент отобразит набор объектов Product, используемых в Web-сервисе, в окне Java, как видно на
рис.
3.18.
Если окно не открылось, выберите File => Tools => Show Java Debug Console (Файл
Сервис
Показать консоль отладки 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




