С появлением поддержки Web-сервисов Lotus Domino Designer 7 продолжает традицию поддержки новых стандартов для расширения возможностей его модели быстрой разработки приложений. Web-сервисы позволяют превратить приложения Lotus Domino в Web-сервисы, базирующиеся на сервере Lotus Domino, таким образом увеличивая возможность доступа к данным и обеспечивая обращение к приложениям через множество различных платформ. Благодаря тому, что все они построены на основе открытых стандартов, Web-сервисы – автономные, модульные приложения, способные работать друг с другом, без необходимости полагаться на соединения, запрограммированные пользователем. Так как Web-сервисы позволяют различным приложениям и информационным системам взаимодействовать друг с другом, серверные компоненты могут быть скомбинированы и рекомбинированы на лету, что позволяет компаниям быстро реагировать на постоянно меняющиеся потребности бизнеса и клиентов.
В этой лекции мы проанализируем, как улучшается приложение ITSO Electronics благодаря использованию Web-сервисов. Для этого рассмотрим следующие темы:
Сервис-ориентированная архитектура (SOA) является компонентной моделью, позволяющей взаимодействовать друг с другом различным функциональным модулям приложения, называемым сервисами, через строго определенный интерфейс (well-defined interface) и набор условий между этими сервисами. Интерфейс определен независимым способом, т. е. он должен быть независим от аппаратной платформы, операционной системы и языка программирования, на котором этот сервис реализован. Таким образом, становится возможным взаимодействие друг с другом сервисов, построенных на различных системах унифицированным и универсальным способом. Так как Web-сервисы характеризуются независимым от платформы подходом к разработке приложения, они являются неотъемлемым компонентом архитектуры SOA-приложения.
Эта особенность, заключающаяся в независимом описании интерфейса, который не строго привязан к конкретной реализации, известна как слабая связь (
Необходимость в системах со слабой связью растет из-за того, что с каждым днем возрастает потребность в более гибких бизнес-приложениях, которая, в свою очередь, основывается на том, что бизнес должен адаптироваться к изменчивости внешней среды, например к постоянно меняющимся принципам стратегии, устойчивости коммерческого положения, бизнес-целям, партнерству, состоянию промышленности, а также другим факторам, связанным с бизнесом, которые оказывают влияние на природу бизнеса. При желании вы можете обратиться к бизнесу, быстро реагирующему на изменения окружающей среды, т. е. к бизнесу по требованию (On Demand Business), который меняется в зависимости от того, как реализуются цели.
Сервис-ориентированная архитектура не только является новшеством, но и представляет собой альтернативную модель более традиционным, жестко связанным (
В настоящее время 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.
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-сервис" характеризуется следующими параметрами:
?OpenWebService: используя протокол HTTP POST, запускает Web-сервис. Если использован протокол HTTP GET, то команда ?OpenWebService вернет некоторую информацию об этом сервисе.?WSDL: запрашивает у Web-сервиса его 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", необходимый для присвоения имени конечной точке сети, связанной с привязкой.
Элемент Web-сервисов Lotus Domino 7 обеспечивает средой для хостинга, основанной на простом протоколе доступа к объектам (SOAP) версии 1.1. SOAP определяет информацию, базирующуюся на XML и используемую для обмена структурированной и классифицированной информацией между равноправными участниками сети в децентрализованной, распределенной среде. Сообщение SOAP, по существу, представляет собой одностороннюю передачу от отправителя к получателю SOAP, однако предполагается, что сообщения SOAP комбинируются с помощью приложений для применения более сложных схем взаимодействия.
Из положения консорциума Всемирной паутины (W3C):
"SOAP is a
("SOAP представляет собой облегченный протокол, предназначенный для обмена структурированной информацией в децентрализованной и распределенной среде. Он основан на протоколе XML, состоящем из трех частей: оболочки, определяющей структуру для описания сообщения и процесса его обработки, набора правил кодирования, служащего для выражения экземпляров типов данных, определенных приложением, и правила, предназначенного для представления удаленных процедурных запросов и ответов".)
В Lotus Domino Designer 7 разработчик приложения может импортировать существующий файл WSDL в приложение и Domino Designer, затем сгенерировать классы на языке LotusScript или Java. Тем не менее, разработчики должны иметь в виду, что не все существующие WSDL-файлы могут быть интерпретированы Lotus Domino Designer 7. Некоторые файлы могут быть отклонены, в зависимости от используемых элементов XML.
Начиная с 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. Пользователь при этом не знает ни о типе базы данных, из которой получает данные, ни об операционной системе, ни о платформе. Пользователи получают доступ, по-видимому, к неограниченному запасу данных, представленному с большой эффективностью.
Используя Web-сервисы и поддержку WSDL, вы можете быстро создавать или расширять код Java или LotusScript, открывая, таким образом доступ к тысячам приложений Lotus Domino из внешних систем, таких как Java 2 Platform, Enterprise Edition (J2EE) и приложениям Microsoft .NET. В этом разделе мы показываем, как улучшаются приложения ITSO Electronics путем внедрения Web-сервисов в среду разработки приложений Lotus Domino.
webservices.nsf и wsconsumer.nsf.Основным нашим требованием по внедрению Web-сервисов в приложение ITSO Electronics стала необходимость в просмотре покупателям и текущей информации о наших продуктах. Web-сервисы лучше всех справятся с подобной задачей. В будущем компания ITSO Electronics планирует использовать Web-сервисы для того, чтобы позволить покупателям получать доступ к информации о счетах, вне зависимости от используемой платформы, операционной системы или интерфейса.
Основным пользователем Web-сервисов приложения ITSO Electronics в нашем примере будет клиент фирмы ITSO Electronics. Приложение необходимо для обеспечения доступа пользователя к текущей информации о продукте через программный механизм и пользовательский интерфейс, интуитивный и легкий в использовании.
Позвольте продемонстрировать вам, насколько легко создать Web-сервис с помощью IBM Lotus Domino Designer 7.
Начнем с исключения ошибок, обработки особых ситуаций, регистрации и производительности. Сосредоточимся на функциональности ядра.
Необходимо, чтобы приложение ITSO Electronics поддерживало и Java, и Lotus-Script.
В этом разделе иллюстрируется создание нового Web-сервиса. В качестве примера используется приложение ITSO Electronics:
(рис 3.1) Окно свойств Web Service
(рис 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
(рис 3.3) Окно свойств Web Service: поле PortType class
(рис 3.4) Окно свойств Web Service: закладка AdvancedДля того чтобы протестировать новый 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-браузере
Приведенная ниже 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".
Существует множество приложений, которые позволяют тестировать и использовать Web-сервисы. Для достижения целей, поставленных в этой книге, мы будем использовать IBM Rational $$\text{\textregistered}$$ Application Developer. Чтобы начать тестирование Web-сервисов, используя 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
(рис 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>
В предыдущем примере было продемонстрировано совместное использование примитивных видов данных, таких как массивы, числа или (как в нашем случае) строки. Требования к приложению 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-сервис, используя Product, который позволит обеспечить партнеров подробной информацией о продуктах. В приведенных ниже действиях обобщается способ создания Web-сервиса.
Shared Code => Web Services (Общий код $$\Rightarrow$$ Web-сервисы). Щелкните по кнопке New Web Service (Создать Web-сервис).Name, введите ProductService, таким образом вы присвоите имя своему Web-сервису. В качестве класса PortType используйте ProductService.Options переключитесь на Java.New Class (Создать класс), после чего замените код предоставляемым по умолчанию кодом, представленным в примере 3.8. Этот код называется ProductService.java.New Class и вставьте код из примера 3.7. Этот код называется Product.java.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>
Документы WSDL экспортируют для того, чтобы предоставить покупателю информацию о том, как использовать созданные Web-сервисы. Во многих случаях инструменты, с помощью которых осуществляется создание клиентов Web-сервисов, могут автоматически генерировать код из документа WSDL.
Для того чтобы экспортировать документ WSDL, выполните следующие действия:
Shared Code => Web Services (Общий код $$\Rightarrow$$ Web-сервисы).ProductService и щелкните по кнопке Export WSDL (Экспортировать документ WSDL).
(рис 3.13) Экспортирование документа WSDLЕсли вы импортируете документ WSDL, описательный класс генерируется на основе содержания документа WSDL. Общедоступные прототипы методов, функций и подстановок в классе соответствуют операциям Web-сервиса, определенным для первого элемента <port> первого элемента <service> в документе WSDL. Другие классы или типы ссылаются на прототипы методов, которые, возможно, также будут сгенерированы на основании содержимого документа WSDL вместе с
Бизнес-партнеры компании ITSO Electronics, а, возможно, и покупатели, в свою очередь, могут обеспечивать компанию документом WSDL, который она может использовать для создания Web-сервисов. Вы можете импортировать существующий документ WSDL, чтобы сгенерировать каркас Web-сервиса. Каркасный код соответствует описанию Web-сервиса. Затем вам необходимо добавить код реализации.
Для того чтобы импортировать документ WSDL, выполните следующее:
Shared Code => Web Services.
(рис 3.14) Импортирование документа WSDL
(рис 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
Операции также могут возвращать ошибки посредством подкласса ошибок, который соответствует некоторому сообщению <wsdl:fault>, выбранному для определенной операции в документе WSDL, или посредством прямого использования базового класса WS_FAULT (LotusScript), или класса lotus.domino.types.Fault, или класса java.lang.Exception(Java).
WS_FAULT ) должны фигурировать в конце списка параметров метода.Ошибки для метода описания сервиса на языке Java возникают в стандартных предложениях Java.
Для получения дополнительной информации о том, как работать с ошибками, используя язык LotusScript см. п. 3.12, "Использование Web-сервисов с помощью LS2J".
Угрозы безопасности 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-сервис). Если выбран этот параметр, пользователи, обладающие открытым доступом к документам в базе данных, получают доступ по умолчанию.На момент написания этой книги Lotus Domino 7.0 обеспечивал, хотя и не в полном объеме, использование Web-сервисов. Тем не менее, вспомогательным бизнес-требованием, предъявляемым к приложению ITSO Electronics, является предоставление доступа к ценовым данным, располагающимся за границами Lotus Domino, что, в свою очередь, диктует необходимость использования Web-сервисов в этом приложении. В нашем сценарии компания ITSO Electronics решила применить программный продукт с открытым исходным кодом
Для того чтобы проиллюстрировать использование Web-сервисов, в нашем сценарии мы создали отдельную базу данных в приложении ITSO Electronics, которую назвали WS Consumer. В этой базе данных содержится агент, который будет использовать сложный Web-сервис, созданный нами ранее.
webservices.nsf и wsconsumer.nsf.Приведенная ниже последовательность действий наглядно иллюстрирует создание агента, использующего Web-сервис.
c:\soap.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>
Shared Code => Agents (Общий код $$\Rightarrow$$ Агенты), после чего щелкните по кнопке New agent (Создать агент).
(рис 3.16) Окно свойств ConsumerWS AgentAgent, затем выберите язык кода Java.JavaBean, представляющий Product, определенный в документе WSDL. Для облегчения этой операции мы воспользуемся возможностью импортирования WSDL для автоматической генерации класса JavaBean. После этого нам необходимо выбрать Shared Code => Web Service (Общий код $$\Rightarrow$$ Web-сервис) и щелкнуть по кнопке New Web Service (Создать Web-сервис).Import WSDL (Импортировать WSDL), затем выберите созданный ранее документ WSDL. В результате импортирования этого документа будут автоматически созданы классы JavaBeansTM.Product.java.New Class (Создать класс). Затем замените класс Untitled.java скопированным кодом Product.java, так же, как это сделано в примере 3.13.Щелкните по кнопке ). Перейдите к нужной директории библиотеки SOAP LIB, в нашем случае эта директория находилась по следующему пути: c:\soap\soap-2_3_1\lib. В качестве типа файла выберите Archive (Архивный), щелкните по кнопке Add/Replace File(s) (Добавить/Заменить файлы), далее нажмите ОК.
(рис 3.17) Окно Organize Java Agent FilesJavaAgent.java по умолчанию заменить своим собственным, чтобы приступить к использованию Web-сервиса, который в нашем сценарии представлен в примере 3.14. Убедитесь в том, что в классе JavaAgent.java есть переменные URL и soapAction. Эти переменные должны указывать на расположение вашего приложения.ConsumeWS.
(рис 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);
}
}
В этом разделе мы расскажем о следующем:
LS2J представляет собой интерфейс, позволяющий переводить данные из типов данных Java в типы данных LotusScript и позволяет LotusScript выполнять методы объектов Java. Благодаря LS2J LotusScript получает способность создавать объекты Java так, будто они были родными для среды LotusScript.
В этом сценарии мы добавили агент LotusScript к базе данных WS Consumer. Агент использует код Java из библиотеки скриптов, для того чтобы использовать Web-сервис.
Web-сервис, который мы используем, способен выполнять одно из двух действий:
WS_FAULT, для того чтобы проиллюстрировать, как Web-сервисы способны отправлять коды ошибок обратно к клиенту.Перечисленные ниже этапы показывают, как создать Web-сервис с помощью LS2J. В этом разделе описывается создание Web-сервиса, а в последующих речь пойдет о создании библиотеки скриптов Java и о том, как она используется в нашем агенте LotusScript через LS2J. Выполните приведенную ниже последовательность действий.
New Web Service.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
(рис 3.19) Окно свойств LS2J Web Service UserInfo
Теперь нам необходимо создать библиотеку скриптов, содержащую класс Java, который будет использовать Web-сервис и сделает его доступным нашему агенту LotusScript через LS2J. Для того чтобы настроить класс Java, необходимо выполнить следующую последовательность действий:
Shared Code (Общий код) и щелкните по кнопке New Java Library (Новая библиотека Java).Apache soap.jar, необходимо вернуться к п. 3.11, "Использование Web-сервисов с помощью Java" для получения дополнительной информации о том, как загрузить Apache SOAP.ConsumeWSLibrary.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; } }
Наконец нам необходимо создать агент LotusScript и использовать только что созданную библиотеку через LS2J.
Navigation выберите Shared Code => Agents.New Agent. В окне свойств нового агента, в поле Name, введите LotusScriptConsumeWS, а в выпадающем списке Target раздела Runtime выберите None. Закройте окно свойств.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
(рис 3.21) Сообщение об ошибке, возникшей при использовании Web-сервиса с помощью LS2JЕсли агент смог использовать ваш Web-сервис, вы увидите сообщение, представленное на рис 3.22.
(рис 3.22) Web-сервис был успешно использован с помощью LS2J
В 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);
В документе WSDL содержится XML-код, который описывает Web-сервис. Привязка WSDL описывает то, как сервис связан с протоколом обмена сообщениями. Привязка WSDL SOAP может быть осуществлена либо при помощи вызова удаленных процедур (RPC), либо при помощи документной привязки. Привязка SOAP также может употребляться как в кодированном виде, так и в литеральном виде. Таким образом, у разработчика приложений Lotus Domino есть четыре типа/моделей использования на выбор:
Терминология "RPC против документального" может сбивать с толку, так как эти термины подразумевают, что тип RPC следует использовать для программируемых моделей RPC и что документальный тип нужно использовать для документальных программируемых моделей или для программируемых моделей обмена сообщениями. Тем не менее, в данном случае все эти заблуждения бессмысленны, так как тип не имеет ничего общего с программируемыми моделями. Типы только диктуют то, как переводить привязку WSDL в сообщение SOAP. Подобно этому, типы кодированный и литеральный имеют значение только в привязке WSDL-к-SOAP.
С появлением поддержки Web-сервисов Lotus Domino Designer 7 продолжает традицию поддержки новых стандартов для расширения возможностей его модели быстрой разработки приложений. Web-сервисы позволяют превратить приложения Lotus Domino в Web-сервисы, базирующиеся на сервере Lotus Domino, таким образом увеличивая возможность доступа к данным и обеспечивая обращение к приложениям через множество различных платформ. Благодаря тому, что все они построены на основе открытых стандартов, Web-сервисы – автономные, модульные приложения, способные работать друг с другом, без необходимости полагаться на соединения, запрограммированные пользователем. Так как Web-сервисы позволяют различным приложениям и информационным системам взаимодействовать друг с другом, серверные компоненты могут быть скомбинированы и рекомбинированы на лету, что позволяет компаниям быстро реагировать на постоянно меняющиеся потребности бизнеса и клиентов.
В этой лекции мы проанализируем, как улучшается приложение ITSO Electronics благодаря использованию Web-сервисов. Для этого рассмотрим следующие темы:
Сервис-ориентированная архитектура (SOA) является компонентной моделью, позволяющей взаимодействовать друг с другом различным функциональным модулям приложения, называемым сервисами, через строго определенный интерфейс (well-defined interface) и набор условий между этими сервисами. Интерфейс определен независимым способом, т. е. он должен быть независим от аппаратной платформы, операционной системы и языка программирования, на котором этот сервис реализован. Таким образом, становится возможным взаимодействие друг с другом сервисов, построенных на различных системах унифицированным и универсальным способом. Так как Web-сервисы характеризуются независимым от платформы подходом к разработке приложения, они являются неотъемлемым компонентом архитектуры SOA-приложения.
Эта особенность, заключающаяся в независимом описании интерфейса, который не строго привязан к конкретной реализации, известна как слабая связь (
Необходимость в системах со слабой связью растет из-за того, что с каждым днем возрастает потребность в более гибких бизнес-приложениях, которая, в свою очередь, основывается на том, что бизнес должен адаптироваться к изменчивости внешней среды, например к постоянно меняющимся принципам стратегии, устойчивости коммерческого положения, бизнес-целям, партнерству, состоянию промышленности, а также другим факторам, связанным с бизнесом, которые оказывают влияние на природу бизнеса. При желании вы можете обратиться к бизнесу, быстро реагирующему на изменения окружающей среды, т. е. к бизнесу по требованию (On Demand Business), который меняется в зависимости от того, как реализуются цели.
Сервис-ориентированная архитектура не только является новшеством, но и представляет собой альтернативную модель более традиционным, жестко связанным (
В настоящее время 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.
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-сервис" характеризуется следующими параметрами:
?OpenWebService: используя протокол HTTP POST, запускает Web-сервис. Если использован протокол HTTP GET, то команда ?OpenWebService вернет некоторую информацию об этом сервисе.?WSDL: запрашивает у Web-сервиса его 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", необходимый для присвоения имени конечной точке сети, связанной с привязкой.
Элемент Web-сервисов Lotus Domino 7 обеспечивает средой для хостинга, основанной на простом протоколе доступа к объектам (SOAP) версии 1.1. SOAP определяет информацию, базирующуюся на XML и используемую для обмена структурированной и классифицированной информацией между равноправными участниками сети в децентрализованной, распределенной среде. Сообщение SOAP, по существу, представляет собой одностороннюю передачу от отправителя к получателю SOAP, однако предполагается, что сообщения SOAP комбинируются с помощью приложений для применения более сложных схем взаимодействия.
Из положения консорциума Всемирной паутины (W3C):
"SOAP is a
("SOAP представляет собой облегченный протокол, предназначенный для обмена структурированной информацией в децентрализованной и распределенной среде. Он основан на протоколе XML, состоящем из трех частей: оболочки, определяющей структуру для описания сообщения и процесса его обработки, набора правил кодирования, служащего для выражения экземпляров типов данных, определенных приложением, и правила, предназначенного для представления удаленных процедурных запросов и ответов".)
В Lotus Domino Designer 7 разработчик приложения может импортировать существующий файл WSDL в приложение и Domino Designer, затем сгенерировать классы на языке LotusScript или Java. Тем не менее, разработчики должны иметь в виду, что не все существующие WSDL-файлы могут быть интерпретированы Lotus Domino Designer 7. Некоторые файлы могут быть отклонены, в зависимости от используемых элементов XML.
Начиная с 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. Пользователь при этом не знает ни о типе базы данных, из которой получает данные, ни об операционной системе, ни о платформе. Пользователи получают доступ, по-видимому, к неограниченному запасу данных, представленному с большой эффективностью.
Используя Web-сервисы и поддержку WSDL, вы можете быстро создавать или расширять код Java или LotusScript, открывая, таким образом доступ к тысячам приложений Lotus Domino из внешних систем, таких как Java 2 Platform, Enterprise Edition (J2EE) и приложениям Microsoft .NET. В этом разделе мы показываем, как улучшаются приложения ITSO Electronics путем внедрения Web-сервисов в среду разработки приложений Lotus Domino.
webservices.nsf и wsconsumer.nsf.Основным нашим требованием по внедрению Web-сервисов в приложение ITSO Electronics стала необходимость в просмотре покупателям и текущей информации о наших продуктах. Web-сервисы лучше всех справятся с подобной задачей. В будущем компания ITSO Electronics планирует использовать Web-сервисы для того, чтобы позволить покупателям получать доступ к информации о счетах, вне зависимости от используемой платформы, операционной системы или интерфейса.
Основным пользователем Web-сервисов приложения ITSO Electronics в нашем примере будет клиент фирмы ITSO Electronics. Приложение необходимо для обеспечения доступа пользователя к текущей информации о продукте через программный механизм и пользовательский интерфейс, интуитивный и легкий в использовании.
Позвольте продемонстрировать вам, насколько легко создать Web-сервис с помощью IBM Lotus Domino Designer 7.
Начнем с исключения ошибок, обработки особых ситуаций, регистрации и производительности. Сосредоточимся на функциональности ядра.
Необходимо, чтобы приложение ITSO Electronics поддерживало и Java, и Lotus-Script.
В этом разделе иллюстрируется создание нового Web-сервиса. В качестве примера используется приложение ITSO Electronics:
(рис 3.1) Окно свойств Web Service
(рис 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
(рис 3.3) Окно свойств Web Service: поле PortType class
(рис 3.4) Окно свойств Web Service: закладка AdvancedДля того чтобы протестировать новый 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-браузере
Приведенная ниже 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".
Существует множество приложений, которые позволяют тестировать и использовать Web-сервисы. Для достижения целей, поставленных в этой книге, мы будем использовать IBM Rational $$\text{\textregistered}$$ Application Developer. Чтобы начать тестирование Web-сервисов, используя 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
(рис 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>
В предыдущем примере было продемонстрировано совместное использование примитивных видов данных, таких как массивы, числа или (как в нашем случае) строки. Требования к приложению 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-сервис, используя Product, который позволит обеспечить партнеров подробной информацией о продуктах. В приведенных ниже действиях обобщается способ создания Web-сервиса.
Shared Code => Web Services (Общий код $$\Rightarrow$$ Web-сервисы). Щелкните по кнопке New Web Service (Создать Web-сервис).Name, введите ProductService, таким образом вы присвоите имя своему Web-сервису. В качестве класса PortType используйте ProductService.Options переключитесь на Java.New Class (Создать класс), после чего замените код предоставляемым по умолчанию кодом, представленным в примере 3.8. Этот код называется ProductService.java.New Class и вставьте код из примера 3.7. Этот код называется Product.java.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>
Документы WSDL экспортируют для того, чтобы предоставить покупателю информацию о том, как использовать созданные Web-сервисы. Во многих случаях инструменты, с помощью которых осуществляется создание клиентов Web-сервисов, могут автоматически генерировать код из документа WSDL.
Для того чтобы экспортировать документ WSDL, выполните следующие действия:
Shared Code => Web Services (Общий код $$\Rightarrow$$ Web-сервисы).ProductService и щелкните по кнопке Export WSDL (Экспортировать документ WSDL).
(рис 3.13) Экспортирование документа WSDLЕсли вы импортируете документ WSDL, описательный класс генерируется на основе содержания документа WSDL. Общедоступные прототипы методов, функций и подстановок в классе соответствуют операциям Web-сервиса, определенным для первого элемента <port> первого элемента <service> в документе WSDL. Другие классы или типы ссылаются на прототипы методов, которые, возможно, также будут сгенерированы на основании содержимого документа WSDL вместе с
Бизнес-партнеры компании ITSO Electronics, а, возможно, и покупатели, в свою очередь, могут обеспечивать компанию документом WSDL, который она может использовать для создания Web-сервисов. Вы можете импортировать существующий документ WSDL, чтобы сгенерировать каркас Web-сервиса. Каркасный код соответствует описанию Web-сервиса. Затем вам необходимо добавить код реализации.
Для того чтобы импортировать документ WSDL, выполните следующее:
Shared Code => Web Services.
(рис 3.14) Импортирование документа WSDL
(рис 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
Операции также могут возвращать ошибки посредством подкласса ошибок, который соответствует некоторому сообщению <wsdl:fault>, выбранному для определенной операции в документе WSDL, или посредством прямого использования базового класса WS_FAULT (LotusScript), или класса lotus.domino.types.Fault, или класса java.lang.Exception(Java).
WS_FAULT ) должны фигурировать в конце списка параметров метода.Ошибки для метода описания сервиса на языке Java возникают в стандартных предложениях Java.
Для получения дополнительной информации о том, как работать с ошибками, используя язык LotusScript см. п. 3.12, "Использование Web-сервисов с помощью LS2J".
Угрозы безопасности 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-сервис). Если выбран этот параметр, пользователи, обладающие открытым доступом к документам в базе данных, получают доступ по умолчанию.На момент написания этой книги Lotus Domino 7.0 обеспечивал, хотя и не в полном объеме, использование Web-сервисов. Тем не менее, вспомогательным бизнес-требованием, предъявляемым к приложению ITSO Electronics, является предоставление доступа к ценовым данным, располагающимся за границами Lotus Domino, что, в свою очередь, диктует необходимость использования Web-сервисов в этом приложении. В нашем сценарии компания ITSO Electronics решила применить программный продукт с открытым исходным кодом
Для того чтобы проиллюстрировать использование Web-сервисов, в нашем сценарии мы создали отдельную базу данных в приложении ITSO Electronics, которую назвали WS Consumer. В этой базе данных содержится агент, который будет использовать сложный Web-сервис, созданный нами ранее.
webservices.nsf и wsconsumer.nsf.Приведенная ниже последовательность действий наглядно иллюстрирует создание агента, использующего Web-сервис.
c:\soap.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>
Shared Code => Agents (Общий код $$\Rightarrow$$ Агенты), после чего щелкните по кнопке New agent (Создать агент).
(рис 3.16) Окно свойств ConsumerWS AgentAgent, затем выберите язык кода Java.JavaBean, представляющий Product, определенный в документе WSDL. Для облегчения этой операции мы воспользуемся возможностью импортирования WSDL для автоматической генерации класса JavaBean. После этого нам необходимо выбрать Shared Code => Web Service (Общий код $$\Rightarrow$$ Web-сервис) и щелкнуть по кнопке New Web Service (Создать Web-сервис).Import WSDL (Импортировать WSDL), затем выберите созданный ранее документ WSDL. В результате импортирования этого документа будут автоматически созданы классы JavaBeansTM.Product.java.New Class (Создать класс). Затем замените класс Untitled.java скопированным кодом Product.java, так же, как это сделано в примере 3.13.Щелкните по кнопке ). Перейдите к нужной директории библиотеки SOAP LIB, в нашем случае эта директория находилась по следующему пути: c:\soap\soap-2_3_1\lib. В качестве типа файла выберите Archive (Архивный), щелкните по кнопке Add/Replace File(s) (Добавить/Заменить файлы), далее нажмите ОК.
(рис 3.17) Окно Organize Java Agent FilesJavaAgent.java по умолчанию заменить своим собственным, чтобы приступить к использованию Web-сервиса, который в нашем сценарии представлен в примере 3.14. Убедитесь в том, что в классе JavaAgent.java есть переменные URL и soapAction. Эти переменные должны указывать на расположение вашего приложения.ConsumeWS.
(рис 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);
}
}
В этом разделе мы расскажем о следующем:
LS2J представляет собой интерфейс, позволяющий переводить данные из типов данных Java в типы данных LotusScript и позволяет LotusScript выполнять методы объектов Java. Благодаря LS2J LotusScript получает способность создавать объекты Java так, будто они были родными для среды LotusScript.
В этом сценарии мы добавили агент LotusScript к базе данных WS Consumer. Агент использует код Java из библиотеки скриптов, для того чтобы использовать Web-сервис.
Web-сервис, который мы используем, способен выполнять одно из двух действий:
WS_FAULT, для того чтобы проиллюстрировать, как Web-сервисы способны отправлять коды ошибок обратно к клиенту.Перечисленные ниже этапы показывают, как создать Web-сервис с помощью LS2J. В этом разделе описывается создание Web-сервиса, а в последующих речь пойдет о создании библиотеки скриптов Java и о том, как она используется в нашем агенте LotusScript через LS2J. Выполните приведенную ниже последовательность действий.
New Web Service.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
(рис 3.19) Окно свойств LS2J Web Service UserInfo
Теперь нам необходимо создать библиотеку скриптов, содержащую класс Java, который будет использовать Web-сервис и сделает его доступным нашему агенту LotusScript через LS2J. Для того чтобы настроить класс Java, необходимо выполнить следующую последовательность действий:
Shared Code (Общий код) и щелкните по кнопке New Java Library (Новая библиотека Java).Apache soap.jar, необходимо вернуться к п. 3.11, "Использование Web-сервисов с помощью Java" для получения дополнительной информации о том, как загрузить Apache SOAP.ConsumeWSLibrary.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; } }
Наконец нам необходимо создать агент LotusScript и использовать только что созданную библиотеку через LS2J.
Navigation выберите Shared Code => Agents.New Agent. В окне свойств нового агента, в поле Name, введите LotusScriptConsumeWS, а в выпадающем списке Target раздела Runtime выберите None. Закройте окно свойств.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
(рис 3.21) Сообщение об ошибке, возникшей при использовании Web-сервиса с помощью LS2JЕсли агент смог использовать ваш Web-сервис, вы увидите сообщение, представленное на рис 3.22.
(рис 3.22) Web-сервис был успешно использован с помощью LS2J
В 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);
В документе WSDL содержится XML-код, который описывает Web-сервис. Привязка WSDL описывает то, как сервис связан с протоколом обмена сообщениями. Привязка WSDL SOAP может быть осуществлена либо при помощи вызова удаленных процедур (RPC), либо при помощи документной привязки. Привязка SOAP также может употребляться как в кодированном виде, так и в литеральном виде. Таким образом, у разработчика приложений Lotus Domino есть четыре типа/моделей использования на выбор:
Терминология "RPC против документального" может сбивать с толку, так как эти термины подразумевают, что тип RPC следует использовать для программируемых моделей RPC и что документальный тип нужно использовать для документальных программируемых моделей или для программируемых моделей обмена сообщениями. Тем не менее, в данном случае все эти заблуждения бессмысленны, так как тип не имеет ничего общего с программируемыми моделями. Типы только диктуют то, как переводить привязку WSDL в сообщение SOAP. Подобно этому, типы кодированный и литеральный имеют значение только в привязке WSDL-к-SOAP.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.