Всего за 399 руб. Купить полную версию
Псевдокод транзакции в среде CORBA
CosTransactions.Current current = CosTransactions.CurrentHelper.Narrow(
orb.ResolveInitialReferences("TransactionCurrent"));
current.Begin();
try
{
store1.Remove(product, quantity);
store2.Append(product, quantity);
current.Commit();
}
catch (Exception e)
{
current.Rollback();
ShowError("Ошибка выполнения операции: " + e.toString());
}
В среде веб-служб в программе-клиенте приходится надстраивать абстракции DTO. А в серверном приложении, где используются соединения, например, с СУБД или монитором транзакций, необходимо фактически дублировать предыдущий код с раскруткой объекта – единицы работы (unit of work) в реальную транзакцию.
Псевдокод транзакции в среде веб-служб
StoreServiceClient storeServiceClient = new StoreServiceClient(url);
StoreOperationDTO operation1 = storeServiceClient.CreateOperation(store1.Id);
operation1.Type = StoreOperations.Remove;
operation1.ProductId = product.Id;
operation1.Quantity = quantity;
StoreOperationDTO operation2 = storeServiceClient.CreateOperation(store2.Id);
operation2.Type = StoreOperations.Append;
operation2.ProductId = product.Id;
operation2.Quantity = quantity;
UnitOfWork uow = new UnitOfWork();
uof.RegisterDirty(operation1);
uof.RegisterDirty(operation2);
try
{
storeServiceClient.ProcessOperations(uow);
}
catch (Exception e)
{
ShowError("Ошибка выполнения операции: " + e.toString());
}
Вторым "упрощением" стал переход от понятных прикладному программисту деклараций интерфейсов объектов и служб на языке IDL к WSDL – описаниям, ориентированным, прежде всего, на обработку компьютером. Сравним декларации складской службы, возвращающей по запросу текущее количество товарных позиций.
Декларация службы в CORBA IDL
module StockServices
{
typedef float CurrentQuantity;
struct QuantityRequest
{
string stockSymbol;
};
interface StockInventoryService
{
CurrentQuantity getCurrent(in QuantityRequest request);
};
};
Декларация службы в WSDL
<?xml version="1.0" encoding="utf-8"?>
<definitions name="StockInventoryService"
xmlns: sqs="http://mycompany.com/stockinventoryservice.wsdl"
xmlns: sqsxsd="http://mycompany.com/stockinventoryservice.xsd"
xmlns: soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns: wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns: xsd="http://www.w3.org/2000/10/XMLSchema">
<wsdl: types>
<xsd: element name="CurrentQuantity">
<xsd: complexType>
<xsd: all>
<xsd: element name="stockSymbol" type="string"/>
</xsd: all>
</xsd: complexType>
</xsd: element>
<xsd: element name="CurrentQuantity">
<xsd: complexType>
<xsd: all>
<xsd: element name="quantity" type="float"/>
</xsd: all>
</xsd: complexType>
</xsd: element>
</wsdl: types>
<xsd: element name="CurrentQuantity">
<xsd: complexType>
<xsd: all>
<xsd: element name="quantity" type="float"/>
</xsd: all>
</xsd: complexType>
</xsd: element>
</wsdl: types>
<wsdl: message name="getCurrentInput">
<wsdl: part name="body" element="sqsxsd: CurrentQuantity"/>
</wsdl: message>
<wsdl: message name="getCurrentOutput">
<wsdl: part name="body" element="sqsxsd: CurrentQuantity"/>
</wsdl: message>
<wsdl: portType name="StockInventoryServicePortType">
<wsdl: operation name="getCurrent">
<wsdl: input message="sqs: getCurrentInput"/>
<wsdl: output message="sqs: getCurrentOutput"/>
</wsdl: operation>
</wsdl: portType>
<wsdl: binding name="StockInventoryServiceSoapBinding"
type="sqs: StockInventoryServicePortType">
<soap: binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl: operation name="getCurrent">
<soap: operation soapAction="http://mycompany.com/getCurrent"/>
<wsdl: input>
<soap: body use="literal"/>
</wsdl: input>
<wsdl: output>
<soap: body use="literal"/>
</wsdl: output>
</wsdl: operation>
</wsdl: binding>
<wsdl: service name="StockInventoryService">
<wsdl: port name="StockInventoryServicePort"
binding="sqs: StockInventoryServiceBinding">
<soap: address location="http://mycompany.com/StockInventoryService"/>
</wsdl: port>
</wsdl: service>
</definitions>
Третьим "усовершенствованием" стал отказ от автоматической подгрузки связанных объектов в пользу исключительно ручного управления процессом.
В CORBA объекты функционируют на сервере, тогда как на клиенте находится только соответствующая заглушка (stub). То есть вы в программе вызываете какой-то метод, а на самом деле происходит обращение к серверу, вызов соответствующего метода у серверного объекта и возврат результата на клиента с возможным обновлением состояния локальных полей заглушки. Аналогично со свойствами объектного типа: связанный объект подгружается по мере необходимости. Всё это происходит прозрачно для программиста, которому не нужно вмешиваться в процесс взаимодействия, но желательно знать, что стоит за манипуляциями с заглушкой на клиенте. Соответственно, существует соблазн вместо реализации на сервере новой функции службы написать код непосредственно на клиенте, благо сделать это легко. Тогда, например, обработка достаточно большой коллекции объектов в цикле может вызвать интенсивный обмен сообщениями с сервером и возникновение узкого места в системе. Аналогичная проблема плохой реализации имеется и при работе приложения напрямую с СУБД.
В среде веб-сервисов вопрос с "нерадивым программистом" решили радикально – отменой самой возможности написать такой код. Несмотря на то что в 80 % случаев имевшаяся автоматическая загрузка была уместной и здорово сокращала программу.
Как уберечь кукурузу от насекомых-вредителей? Очень просто: выкосить её всю, к чертям. Вредители придут, а кушать нечего.
Возвращаемые веб-службами объекты не связаны с серверными за их отсутствием. Потому что у серверной части приложения нет состояния и, соответственно, не может быть никаких объектов в принципе. Обмен сообщениями происходит как и в обычной веб-среде: запрос – ответ без поддержки сессии. Общеупотребительная практика – использование DTO для передачи состояния объектов от клиента к серверу и обратно. Но DTO не содержит никаких ссылок на другие объекты, кроме вложенных. Его структура состоит из полей скалярных типов, разрешённых стандартом, вложенных объектов и массивов. Соответственно, вы не можете прозрачным образом динамически подгрузить недостающий объект, для чего придётся явным образом вызывать службу.
Прозрачная загрузка объектов в клиентском CORBA-приложении
BookGroup group = catalog.getBookCategory("Программирование");
Book[] books = group.getItems(); // один вызов сервера
foreach(Book book in books)
{
ShowInfo(book.Name +": ");
ShowInfo(book.getPopularity(). getVotesCount()); // два вызова
}
Работа клиентского приложения с DTO в среде веб-служб
BookGroupServiceClient groupClient = new BookGroupServiceClient(url1);