Глава 29

Технология MIDAS

Введение

MIDAS — это сокращение от Multitier Distributed Applications Services, что переводится, как набор сервисов для многозвенных распределенных приложений. Разработка многозвенных распределенных приложений средствами Delphi является наиболее высокоэффективным и быстрым средством для создания корпоративных систем. Технология MIDAS позволяет получать доступ к данным, физически расположенным на разных машинах, распределять нагрузку ресурсов по сети, автоматически получать ограничения на данные, что позволяет уменьшить сетевой "траффик", а также разделить бизнес-логику приложения на менее уязвимые части. Приложения MIDAS легко и быстро разрабатывать благодаря основным компонентам, реализующим технологию:

С помощью MIDAS можно создавать системы, которые могут обрабатывать запросы Internet-приложений. MIDAS работает одинаково хорошо с технологиями CORBA, СОМ, OLEnterprise и MTS и упрощает интеграцию существующих систем.

За последнее время технология MIDAS претерпела сильные изменения, что говорит о ее стремительном развитии и большой популярности, в качестве инструмента для создания многозвенных распределенных приложений. В рамках Delphi 5 в технологию MIDAS введены новые компоненты, свойства, и события. Основные изменения затронули интерфейс IProvider, и соответственно объект TProvider, пулинг удаленного модуля данных, работу с сокетами и соответственно компонент TSocke [.Connection. Добавились такие новые возможности, как создание Web MIDAS клиента, возможность организовать связь с сервером приложений через протокол HTTP, реализация доступа к ограничениям базы данных.

Изменения коснулись и установки приложений MIDAS. Теперь нет необходимости в библиотеке STDVCLNN.DLL, а вместо DBCLIENT.DLL используется MIDAS.DLL.

Теперь рассмотрим подробнее все эти новшества и изменения, а также затронем основные механизмы работы и создания многозвенных приложений, как серверов приложений, так и клиентов. Сначала рассмотрим базовые компоненты технологии MIDAS.

Создание многозвенного приложения

Многозвенное приложение представляет собой распределенные системы удаленного доступа к данным, которые состоят как минимум из трех логических уровней. Эти логические уровни могут находиться как на одной, так и на нескольких машинах. Применение многозвенных приложений позволяет обеспечить несколько преимуществ.

В самой простой форме, так называемой "three-tiered model", используются следующие уровни.

Средствами Delphi можно создать первый и второй уровень, а для третьего воспользоваться уже существующими RDBMS.

Взаимодействие этих уровней осуществляется следующим образом. Пользователь запускает клиентское приложение. Клиент соединяется с сервером приложений (который может определяться как во время исполнения, так и во время создания приложения). Запускается сервер приложений. Клиент получает интерфейс IAppServer от сервера приложений.

Затем клиент запрашивает данные от сервера приложений. В свою очередь сервер приложений запрашивает данные (устанавливая, если необходимо, соединение) в базе данных, упаковывает их для клиента, и возвращает пакет данных клиенту. Клиент расшифровывает пакеты данных и предоставляет их пользователю. Пользователь взаимодействует с клиентским приложением, и данные изменяются. Клиент упаковывает измененные данные в пакеты и отсылает их на сервер приложений.

Сервер приложений расшифровывает пакеты и сохраняет изменения в контексте транзакции. Если запись не может быть сохранена на сервере, сервер пытается согласовать изменения с текущими данными и отделяет данные, которые не могут быть сохранены. Когда процесс обработки измененных данных закончен, сервер возвращает все несохраненные данные клиенту для дальнейшего уточнения.

Клиент уточняет необработанные данные, после чего посылает их снова серверу приложений. Затем клиент обновляет свои данные с сервером.

Рассмотрим весь механизм создания трехзвенного приложения средствами Delphi. Сначала необходимо создать сервер приложений. Его создание похоже на создание простого обыкновенного сервера в приложении клиент-сервер. Отличие заключается в том, что надо добавить провайдер данных.

Для создания сервера приложений, начните новый проект, сохраните его и сделайте следующее:

  1. Добавьте новый удаленный модуль данных. Из основного меню File выберите команду New, затем страницу Multitier и на ней необходимый тип.
  2. Разместите соответствующий компонент набора данных на модуль данных и установите его на доступ к базе данных сервера.
  3. Разместите компонент TDataSetProvider на модуле данных для каждого набора данных.
  4. Установите свойство DataSet для каждого провайдера.
  5. Напишите код для обработки событий, бизнес-правил, проверки данных и обеспечения безопасности.
  6. Сохраните, скомпилируйте, зарегистрируйте (или установите) сервер приложений.
  7. Если сервер не использует DCOM, то вы должны инсталлировать дополнительные средства для получения сообщений клиента, инициирования удаленного модуля данных и управления вызовами интерфейса.

После создания сервера приложений, его необходимо зарегистрировать. Если сервер приложений использует как коммуникационный протокол DCOM, HTTP, sockets или OLEnterprise, то он действует как сервер автоматизации и должен быть зарегистрирован подобно любому другому ActiveX- или СОМ-серверу. Если вы используете MTS, сервер приложений должен быть реализован в виде динамической библиотеки. Поскольку все вызовы СОМ должны проходить через MTS-прокси, нельзя просто зарегистрировать сервер приложений. Вместо этого следует инсталлировать библиотеку в среде MTS.

Когда сервер приложений использует CORBA, регистрация не всегда необходима. Если вы хотите позволить клиенту использовать динамическое связывание с вашим интерфейсом, вы должны инсталлировать интерфейс сервера в репозиторий интерфейсов. В дополнение к сказанному, если вы хотите позволить клиенту запускать сервер, если тот еще не запущен, он должен быть зарегистрирован с OAD (Object Activation Daemon).

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

Для создания многозвенного клиентского приложения в среде Delphi необходимо сделать следующее.

  1. Добавить новый модуль данных в проект.
  2. Поместить компонент связи на модуль данных.
  3. Установить свойства компонента связи, определяющие сервер приложений, с которым будет установлено соединение.
  4. Установить свойства других компонентов связи, если в этом есть необходимость. Например, вы можете установить свойство objectBroker, которое позволяет компоненту связи выбирать динамически один из нескольких доступных серверов.
  5. Поместить столько компонентов TclientDataSet на модуль данных, сколько потребуется и установить свойство RemoteServer для каждого компонента соответственно, которые мы поместили в шаге 2.
  6. Установить свойство ProviderName для каждого компонента TclientDataSet. Если ваш компонент связи подсоединен к серверу приложений во время дизайна, то вы можете выбрать значение свойства из списка.

Порядок действий очень важен. Вы должны создать и запустить сервер приложений перед созданием клиента. На этапе разработки вы можете подсоединиться к серверу и протестировать клиента. Вы можете, конечно, создавать клиента и без привязки к серверу во время разработки и использовать его только в готовом варианте. Однако в этом случае вы заранее не видите, работает ли клиент так, как вы того хотите, и не можете выбирать сервер и провайдер из списка в Инспекторе объектов.

Если вы создаете клиента в той же системе, что и сервер, и не используете Web-соединение или сокет-соединение, вы можете захотеть зарегистрировать или инсталлировать сервер приложений на клиенте. Это позволяет компонентам связи использовать сервер приложений во время разработки таким образом, что можете выбирать имя сервера и провайдера из списка в Инспекторе объектов. Если же вы используете Web-соединение или сокеты, то компоненты связи получают имена зарегистрированных серверов с серверной машины.

Рассмотрим дальше, как можно усовершенствовать основную многозвенную архитектуру для поддержки специальных функций в приложении:

В качестве дополнительных возможностей интерфейса сервера приложений можно добавить:

Если вы хотите создать клиентов на основе Web для вашего многозвенного приложения, вы должны клиентское звено заменить на специальное Web-

приложение, которое действует одновременно и как клиент для сервера приложений, и как приложение Web-сервера, которое инсталлировано на одной и той же машине с Web-сервером.

Существует два варианта построения Web-приложения MIDAS.

Эти два варианта сильно отличаются. Каждый из них ориентирован на свою технологию (ActiveX против JavaScript и XML). Для выбора варианта необходимо ориентироваться на пользователя. Первый вариант требует, чтобы броузер поддерживал ActiveX (это ограничивает выбор клиентом операционной системы, офаничивая его разновидностями Windows). Второй вариант требует поддержки языков JavaScript и DHTML.

Сервер приложений

Сервер приложений относится к программному обеспечению промежуточного слоя (middleware). Он предназначен для обеспечения соединения с клиентами, управления доступом клиентов к данным, выполнения бизнес-логики приложения. При обращении к серверу баз данных сервер приложений чаще всего использует BDE. При работе с клиентами функциональные возможности сервера приложений зависят от типа соединения в рамках технологии MIDAS. Сервер приложений включает в себя удаленный модуль данных, который обеспечивает работу интерфейса IAppserver, которого в свою очередь использует клиент для общения с провайдерами данных. Существует три типа удаленных модулей данных:

Со всеми этими типами модулей данных можно использовать невизуальные компоненты. Удаленный модуль данных включает в себя провайдер данных для каждого набора данных на сервере приложений, делая их доступными для клиента. Провайдер данных:

Обычно провайдер для работы с данными использует средства BDE или ADO.

Интерфейс IAppServer

Замена в Delphi 5 интерфейса iprovider на lAppServer является основным и серьезным изменением в технологии MIDAS по сравнению с предыдущей версией. При этом эти интерфейсы остались похожи по своим функциям.

 

Листинг 29.1 Описание интерфейса IAppServer

type

IAppServer = interface(IDispatch)

['( 1AEFCC20-7A24-11D2-98BO-C69BEB4B5B6D )']

function AS_Apply(Jpdates(const ProviderName: WideString;

Delta: OleVariant; MaxErrors: Integer;

out ErrorCount: Integer; var OwnerData: OleVariant):

OleVariant; safecall;

function AS GetRecords(const ProviderName: WideString;

Count: Integer; out RecsOut: Integer; Options: Integer;

const CommandText: WideString; var Params: OleVariant;

var OwnerData: OleVariant): OleVariant; safecall;

function AS_DataRequest(const ProviderName: WideString;

function AS GetProviderNames: OleVariant; safecall;

Data: OleVariant): OleVariant; safecall;

function AS_GetParams(const ProviderName: WideString;

var OwnerData: OleVariant): OleVariant; safecall;

function AS RowRequest(const ProviderName: WideString;

Row: OleVariant; RequestType: Integer;

var OwnerData: OleVariant): OleVariant; safecall;

procedure AS Execute(const ProviderName: WideString;

const CommandText: WideString; var Params: OleVariant;

var OwnerData: OleVariant); safecall;

end;

Iappserver — это интерфейс, который набор данных клиента использует для общения с провайдером на сервере приложений. Этот интерфейс обеспечивает основу коммуникаций для многозвенных приложений. Наборы данных клиента получают экземпляр IAppServer от компонента связи в клиентском приложении.

Используя IAppServer, набор данных клиента общается с провайдером на удаленном сервере приложений. По умолчанию интерфейс является "stateless", это означает, что вызовы функции независимы и не привязаны к предыдущему вызову. Поэтому интерфейс IAppServer не имеет свойств, которые бы хранили информацию о состоянии между вызовами. Однако есть случаи, в которых набор данных клиента полагается на сохраненную информацию о состоянии, такую как текущая позиция курсора базы данных, когда выполняется постепенно возрастающая выборка, использующая метод as_getrecords. Эта информация о состоянии сохраняется только, если несколько клиентов не использует совместно сервер приложений, который реализует IAppServer.

Основным отличием нового интерфейса от iprovider является то, что IAppServer сводит к меньшему число вызовов туда и обратно для завершения сеанса связи, и он не содержит информации о состоянии. Но это не значит, что уже нельзя использовать "stateful" код в своих приложениях.

На практике это означает, что вместо щелчка правой кнопкой мыши по компоненту TDataSetProvider и выбора свойства Export provider из модуля данных, устанавливается значение свойства TDataSetProvider. Exported: = True для любого Datasetprovider, который надо экспортировать. Это также означает, что надо связать TDataSet с TDataSetProvider и экспортировать TDataSetProvider в MIDAS. Это основное отличие от прошлых версий не очень трудоемкое, чтобы отказываться от предоставленной возможности увеличить гибкость компонента TDataSetProvider. Для таких компонентов используется интерфейс lAppServer для сканирования списка провайдеров. Для клиента нет никаких изменений, порядок действия остается

Прежним: устанавливается значение cвойств ClientDataset.RemoteServer и ClientDataset.ProviderName.

Однако минус этих изменений заключается в том, что теперь необходимо переориентировать старые клиентские приложения на использование IAppServer.

Свойства и методы интерфейса lAppServer представлены в табл. 29.1.

Таблица 29.1. Свойства и методы интерфейса lAppserver

Метод

Описание

function AS ApplyUpdates(con5t ProviderName: WideString; Delta: OleVariant; MaxErrors:

Integer; out ErrorCount: Inte

ger; var OwnerData: OleVari-

ant): OieVariant; safecall; 

Принимает изменения, полученные от клиентского набора данных, используя указанного провайдера.

AS ApplyUpdates возвращает Variant,nкоторый является пакетом данных, содержащим все записи, которые не могли примениться к базе данных

function AS DataRequest(const ProviderName: WideString; Data: OleVariant): OleVariant; safecall;

Генерирует событие OnDataRequest для указанного провайдера

procedure AS Execute(const ProviderName: WideString; const CommandText: WideString; var

Params: OleVariant; var OwnerData: OleVariant); safecall;

Выполняет запрос или сохраненную процедуру для указанного провайдера

function AS GetParams(const ProviderName: WideString; var OwnerData: OleVariant): Ole

Variant; safecall;

Выбирает текущие значения параметра из набора данных по указанному провайдеру

function AS GetProviderNames: OleVariant; safecall;

Возвращает список всех доступных провайдеров удаленного модуля данных

function AS GetRecords(const ProviderName: WideString, Count: Integer; out RecsOut:

Integer; Options: Integer;

const CommandText: WideString;

var Params: OleVariant; var

OwnerData:OleVariant): OleVari

ant; safecall;

Возвращает пакет данных, который содержит уточненные данные

function AS RowRequest(const ProviderName: WideString; Row: OleVariant; RequestType: Inte

ger; var OwnerData: OleVariant): OleVariant; safecall;

Возвращает информацию от указанной записи набора данных провайдера

Вместе с заменой интерфейса i provider, удален и компонент TProvider. Его теперь нет в палитре компонентов, и в библиотеке VCL он оставлен только для совместимости. Причина этого удаления — введение нового интерфейса IProviderSupport.

Любой потомок класса TDataSet, который хочет участвовать в работе многозвенного приложения как провайдер MIDAS, должен реализовать соответствующие методы IProviderSupport. Когда провайдер должен получить информацию или принять изменения, используется выполнение методов интерфейса IProviderSupport ДЛЯ TDataSet.

Свойства и методы интерфейса IProviderSupport представлены в табл. 29.2.

Таблица 29.2. Свойства и методы интерфейса JproviderSupport

Метод

Описание

procedure PSExecute;

Выполняет команду SQL, связанную с набором

 

 

данных. Если нет SQL-текста для выполнения, PSExecute вызывает исключительную ситуацию

EDATABASEERROR

function

PSExecuteStatement(const

ASQL: string; AParams:

TParams; ResultSet:

Pointer = nil): Integers;

Выполняет указанную команду SQL. Если значение ResolveToDataSet равно False, компонент провайдера неявно вызывает PSExecuteStatement, чтобы выполнить текст

SQL, который генерируется для принятия изменений. Обычно набор данных передает этот текст на сервер базы данных для выполнения

procedure

PSGetAttributes(List: TList) ;

Возвращает информацию, которая сохранена в пакетах данных как пары Name/Values. Провайдер вызывает PSGetAttributes, чтобы прибавить информацию о наборе данных к метаданным, сохраненным с пакетами данных

function PSGetDefaultOrder: TIndexDef;

Возвращает определение индекса, который указывает заданный по умолчанию порядок сортировки для записей, когда они появляются в клиентском наборе данных

function PSGetIndexDefs

(IndexTypes: TindexOptions;[ixPrimary ..ixNonMaintained]): TIndexDefs;

Возвращает определения всех указанных индексов, которые есть у набора данных. Эта информация позволяет провайдеру располагать записи, которые должны измениться. Провайдер также вызывает этот метод для расположения индексов, которые добавляются к метаданным пакетов данных

function PSGetKeyFields:

string;

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

function PSGetParams:

TParams;

Возвращает объект TParams, который описывает

текущие значения всех параметров набора данных. Если набор данных не имеет никаких параметров, PSGetParams возвращает Nil 1

function PSGetQuoteChar:

strings;

Возвращает символ или символы, чтобы использовать их в сгенерированных командах SQL для включения строк в кавычках

function PSGetTablename: string;

Возвращает название таблицы набора данных, которая появляется в сгенерированных командах SQL

function PSGetUpdateEx-ception(E: Exception; Prev: EUpdateError): EUpdateError;

Генерирует объект EupdateError, основанный на другом объекте исключения

function PSInTransac-tion: Boolean;

Указывает, происходят ли действия с набором данных в контексте транзакции

function PSIsSQLBased: Boolean;

Указывает, включает ли набор данных "native" поддержку SQL. Даже если набор данных не основан на SQL, это может все же позволять провайдеру выполнять команды SQL для принятия изменений. Например, локальные базы данных типа Paradox и DBASE обеспечивают поддержку SQL через BDE, но не базируются на SQL

function PSIsSQLSup-ported: Boolean;

Указывает, может ли набор данных выполнять команды SQL

procedure PSReset;

Сбрасывает набор данных так, чтобы он был позиционирован на первую запись. Провайдер вызывает PSReset, чтобы снова установить набор данных на первой записи перед выборкой записей

procedure PSSetCommand-Text(const CommandText: string) ;

Определяет указанную команду SQL для выполнения при вызове PSExecute

procedure PSSetPar-ams(AParams: Tparams);

Назначает значения параметра, указанные AParams к параметрам набора данных

procedure PSStartTransaction;

procedure PSEndTransac-tion(Commit: Boolean);

Компонент провайдера принимает изменения в пределах транзакции, если это возможно. Для этого вызывается PSStartTransaction, чтобы запустить транзакцию перед принятием изменений, и PSEndTransaction, когда все изменения приняты или возникают ошибки

function PSUpdateRe-cord(UpdateKind: TUp-dateKind; Delta: TData-Set): Boolean;

Принимает одно изменение к основной таблице базы данных или таблицам

Удаленный модуль данных

При создании удаленного модуля данных необходимо указать, как он должен отвечать на клиентские запросы. Эта информация изменяется в зависимости от типа удаленного модуля данных. Чтобы добавить компонент TRemoteDataModule к приложению, надо выбрать пункт New меню File и затем значок Remote Data Module со страницы Multitier (рис. 29.1).

Рис. 29.1. Создание удаленного модуля данных начинается с выбора компонента Remote Data Module

Затем надо указать имя класса удаленного модуля данных. Оно также будет и именем интерфейса данного класса.

При создании библиотеки DLL надо определить потоковую модель в мастере создания Remote Data Module. Можно выбрать Single-threaded, Apartment-threaded, Free-threaded или Both. При создании отдельного ЕХЕ-файла надо определить свойство instancing. Можно выбрать single instance или Multiple instance.

Непосредственным предком удаленного модуля данных является обычный модуль данных. Унаследованные от него механизмы обеспечивают взаимодействие компонентов доступа к данным с сервером баз данных через BDE. Собственные механизмы удаленного модуля данных обеспечивают взаимодействие с клиентами.

Удаленный модуль данных поддерживает дуальный интерфейс сервера автоматизации, который реализует интерфейс IAppserver.

Свойства и методы TRemoteDataModule представлены в табл. 29.3.

Таблица 29.3. Свойства И методы класса TRemoteDataModule

Объявление

Описание

Property Providers[const ProviderName: string]: TCustomProvider;

Содержит список провайдеров, доступных для данного удаленного модуля данных

Function GetProvider(const ProviderName: string): TCustomProvider; virtual;

Возвращает зарегистрированного провайдера по его имени

Procedure Lock; virtual;

Блокирует удаленный модуль данных от использования другими потоками. Блокировка использует критическую секцию, чтобы принять меры против конфликтов потоков. Это означает, что любой код, который обращается к свойствам удаленного модуля данных или к содержащимся объектам, должен вызвать блокировку, иначе это приведет к конфликтам потоков

Procedure Unlock; virtual;

Разблокирует удаленный модуль данных после того, как он был заблокирован методом Lock

Procedure Register-Provider(Value: Tcustom-Provider); virtual;

Добавляет провайдера к списку, возвращаемому A3 GetProviderNames

Procedure UnRegister-Provider(Value: TCustomProvider) ; virtual/

Удаляет провайдера из списка, возвращаемого as GetProviderNames

Class procedure UpdateReg-istry (Register: Boolean; const ClassID, ProgID: string); override;

Регистрирует удаленный модуль данных в системном реестре как сервер автоматизации

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

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

В данной версии технологии MIDAS реализован пулинг экземпляров удаленного модуля данных. Для этого надо вызвать Registerpooied из метода updateRegistry наследника TRemoteDataModule. После этого сервер приложений организует кэш для экземпляров удаленного модуля данных. Каждый клиентский запрос обслуживается первым доступным экземпляром из этого кэша. Поскольку экземпляры разделены, удаленный модуль данных не может использовать информацию о состоянии.

Компонент TDataSetProvider

Использование компонента TDataSetprovider обеспечивает клиента данными из БД и организует обратную передачу измененных данных. TDataSetprovider обычно используется на сервере приложений. Он служит брокером данных между удаленным сервером базы данных и набором данных клиента на клиенте.

TDataSetprovider упаковывает данные из множества данных и переправляет их в один или несколько пакетов для клиента. Клиент получает пакеты данных и реконструирует их в локальные данные. Когда пользователь прекратит работу с данными, клиент переупакует измененные данные и отправит их обратно на сервер.

Свойства и методы TDataSetprovider представлены в табл. 29.4

Таблица 29.4. Свойства и методы класса TDataSetprovider

Свойство

Описание

property Constraints: Boolean;

Это свойство определяет, будут ли посылаться ограничения на данные клиенту или нет. Посылка ограничений позволяет множеству данных клиента проверять ограничения локально, таким образом, снижается вероятность отказа при применении изменений на сервере

property DataSet: TdataSet;

 

Указывает набор данных, для которого провайдер представляет данные и к которому будут применяться изменения. Надо определить DataSet для связывания провайдера набора данных с набором данных, которыйон представляет. Провайдер набора данных упаковывает записи из набора данных в пакеты данных, которые могут использоваться клиентскими наборами данных. Чтобы создать пакеты данных, если используется провайдер, должен быть определен набор данных

property Exported: Boolean;

Позволяет клиентским приложениям передавать запросы провайдеру. Использование этого свойства определяет, сделан ли провайдер доступным клиенту

property ResolveToDataSet: Boolean;

Определяет, должны ли изменения примениться к набору данных или непосредственно на сервер базы данных. Это может быть полезным, если приложение использует события на компоненте набора данных, или если набор данных не представляет данные от сервера базы данных (например, клиентский набор данных)

property Resolver: TCustomResolver; 

Провайдер использует Resolver, чтобы обработать подробности применения изменений и разрешить ошибки этих изменений. Большинство приложений не должно использовать решающее устройство непосредственно

property Options: TProviderOptions;

property Data: OleVariant;

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

  • Включены ли вложенные detail наборы и данные BLOB в пакеты данных или выбраны отдельно.
  • Включают ли пакеты данных свойства поля типа форматов, названия, и максимум и минимальные значения.
  • Для каких операций доступны пакеты: только чтение, чтение и запись или заблокированы на конкретный тип изменений (вставка, редактирование, удаление).
  • Должны ли изменения "master"-таблицы повлечь за собой соответствующие модификации "detail"-таблицы

Указывает пакет данных для провайдера. Это свойство только для чтения, и потому обеспечивает доступ к пакету, содержащему все записи. Для получения этого свойства вызывают GetRecords с параметром -1

Клиентская часть

Для конечного пользователя клиентская часть многозвенного приложения выглядит и работает точно так же, как и в традиционном двухзвенном приложении, которое использует кэшированные изменения. По структуре клиентская часть представляет собой приложение, которое работает без BDE и позволяет использовать набор данных клиента в режиме работы с файлами. Для работы такому клиенту необходима только библиотека MIDAS.DLL. Используя только эту библиотеку, такие приложения легче распространять; не надо инсталлировать, конфигурировать и поддерживать программное обеспечение для управления соединениями с базой данных.

Поскольку эти приложения не используют базу данных напрямую, они не поддерживают многопользовательский вариант работы. Вместо этого наборы данных полагаются на самостоятельную реализацию приложением работы с несколькими пользователями. Данные могут быть сохранены в файл на диске и в дальнейшем загружены, но не существует встроенной защиты для предотвращения перезаписи несколькими пользователями файлов данных друг друга.

Для представления набора данных клиент использует компонент TClientDataSet. Этот компонент содержит все свои данные в памяти, поэтому клиент не может работать с очень большими наборами данных (размер данных зависит от размера памяти у машины клиента).

Наборы данных клиента обеспечивают все виды работы с данными: доступ к данным, редактирование, перемещение по записям, поддержку фильтрации, которые предусмотрены компонентом TDataSet. Дополнительно к этому набор данных клиента имеет свои механизмы для записи и чтения данных, такие как:

Интерфейс lAppServer предоставляет собой мост между клиентской частью и провайдерами серверной части. Большинство клиентов не используют lAppServer напрямую, а вызывают методы и свойства через наборы данных клиента. Однако когда в этом есть необходимость, его можно и прямо вызвать, используя свойство AppServer. Клиент получает этот интерфейс от компонента связи.

Компонент TCIientDataSet

Прямым предком этого компонента является класс TDataSet, который обеспечивает потомка всеми возможностями по работе с набором данных. Работа с набором данных подобна аналогичной работе стандартных компонентов доступа к данным. Существенные отличия имеются в методах редактирования и записи данных, так как компонент поддерживает связь с сервером баз данных при посредстве сервера приложений и интерфейса IAppServer.

Технология MIDAS получила и в этом месте свое дальнейшее развитие. По отношению к компоненту TCIientDataSet, изменения связаны с заменой IProvider на IAppServer и некоторых других свойств.

Свойство provider, options получило дополнительно много других новых опций и значений. Наиболее интересные из них — poDisbaieinserts, poDisableEdits И poDisableDeletes. Устанавливая это свойства соответственно, можно защитить TСlientDataset, который связан с этим провайдером от вставки, редактирования или удаления записей. Это предоставляет новую возможность по работе с бизнес-логикой и безопасностью работы сервера.

Возможность посылать динамический SQL-запрос серверу упростилась. Для этого появилось новое cвойство ClientData5et.CommandText, с помощью которого можно посылать команду на SQL от клиента серверу. Для выполнения команды на сервере необходимо установить значение свойства Provider. Options. poAllowCommandText равным True И далее Вызвать Либо метод Open, либо метод Execute.

С добавлением свойства Provider. Options.poPropogateChanges, любое изменение данных на сервере приложений будет автоматически возвращено клиенту и обновлено с текущими данными в TClientDataset.

Наиболее важные свойства и методы TClientDataSet представлены в табл. 29.5.

Таблица 29.5. Свойства и методы класса TClientDataSet

Объявление

Описание

property Active: Boolean;

Возвращает состояние набора данных. При значении True набор данных открыт

property AppServer: IAppServer;

Обеспечивает доступ к интерфейсу сервера приложений

property CanModify: Boolean;

Показывает, можно ли редактировать записи в наборе данных

property ChangeCount: Integer;

Содержит число изменений, произведенных в на боре данных с момента последнего обновления данных

property CloneSource: TClientDataSet;

Указывает набор данных клиента, с которым данный набор данных разделяет данные

property CommandText: string;

Определяет команду SQL для выполнения на сервере

property Data: OleVariant;

Представляет набор данных в транспортном формате, связанного с компонентом интерфейса

property DataSetField: TDataSetField;

Ссылка на компонент TDatasetField, который указывает на поле главного набора данных, для которого этот набор данных является ложенным

property DataSize: Integer;

Содержит размер пакета в байтах

property DataSource: TDataSource;

Ссылка на компонент TDataSource, который используется для организации отображения данных

property FetchOnDemand: Boolean;

Определяет режим загрузки данных с сервера. При значении True данные поступают автоматически

property FileName: string;

Определяет имя локального файла, в котором сохраняются данные

property HasAppServer:

Boolean;

 

 

Указывает, связан ли набор данных клиента с удаленным сервером приложений. HasAppServer используется для определения, получает ли наборданных клиента данные от интерфейса IAppServer. Когда значение свойства HasAppServer равно True, клиент может взаимодействовать с провайдером на удаленном сервере приложений или локальных провайдерах в том же самом процессе через интерфейс IAppServer

property PacketRecords: Integer;

Определяет число записей в пакете

property ProviderName: string;

Содержит имя провайдера интерфейса

property RecNo: Integer-property RecordSize: Word;

Содержит порядковый номер текущей записи Возвращает размер одной записи

property RemoteServer: TCustomRemoteServer;

Определяет компонент связи с сервером приложений

property SavePoint: Integer;

property StatusFilter: TUpdateStatusSet;

procedure Append-Datafconst Data: Ole-Varian-l-; HitEOF: Boolean) ;

Возвращает текущую позицию процесса изменений. Используется как закладка, при помощи которой можно вернуться к этому месту изменений

Определяет тип допустимых изменений набора данных

Добавляет новый пакет данных Data в набор данных клиента. Параметр HitEOF показывает, достигнут ли конец набора данных

function ApplyUp-dates(MaxErrors: Integer) ; Integer; virtual;

Передает все измененные записи на сервер. Параметр MaxErrors определяет максимально возможное число ошибок

procedure CancelUpdates;

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

procedure CloneCur-sor(Source :TClientDataSet; Reset: Boolean; KeepSettings: Boolean = False);

Делает доступным текущий набор данных в наборе данных Source. Все изменения отображаются сразу в двух наборах данных

procedure CreateDataSet;

procedure EmptyDataSet;

procedure Execute; virtual;

Создает новый набор данных на основе свойств текущего

Удаляет из набора данных все записи Выполняет команду SQL на сервере приложений

procedure FetchBlobs;

Получает от сервера данные в формате BLOB. Этот метод не используется, если свойство

FetchOnDemand имеет значение True

procedure FetchDetails;

Получает вложенные наборы данных от сервера. Этот метод не используется, если свойство

FetchOnDemand имеет значение True

procedure LoadFrom-File(const FileName: string = '');

Загружает из файла сохраненный набор данных

procedure MergeChangeLog;

Возвращает все накопленные изменения обратно в набор данных

procedure Post; override;

Сохраняет текущую запись. В зависимости от значения свойства LogChanges, изменения сохраняются или переносятся сразу в свойства Data

procedure Save-ToFile(const FileName: string = ''; Format TDa-taPacketFor-mat==dfBinary) ;

Сохраняет набор данных клиента в файле

function UndoLast-Change(FollowChange: Boolean): Boolean;

Отменяет последнее изменение набора данных клиента

function UpdateStatus: TUpdateStatus; override;

Возвращает состояние текущей записи набора данных клиента

Соединение с сервером приложений

Основная цель компонентов связи — TDCOMConnection, TSocketConnection, TWebConnection, TOLEnterprj seConnection, TCorbaConnection — состоит В том, чтобы найти и соединиться с сервером приложений. Поскольку они управляют соединениями сервера, можно также использовать компоненты связи для вызова методов интерфейса сервера приложений.

Различные компоненты используют свои протоколы коммуникации. Соответствие между компонентами и протоколами отображено в табл. 29.6

Таблица 29.6. Протоколы, используемые компонентами связи

Компонент

Протокол

TDCOMConnection

DCOM

TsocketConnection

Windows sockets (TCP/IP)

TWebConnection

HTTP

TOLEnterpriseConnection TCorbaConnection

OLEnterprise (RPCs) CORBA (HOP)

 Перед поиском и соединением с сервером приложений необходимо установить свойства компонента связи, которые однозначно определяют сервер приложений.

Соединение открывается автоматически, когда набор данных клиента обращается к серверу приложений. Компонент связи разрывает соединение с сервером приложений, когда:

Можно использовать вместо одного компонента связи для переключения между серверами приложений несколько компонентов связи.

Приложениям нет необходимости вызывать интерфейс IAppServer непосредственно, потому что соответствующие запросы делаются автоматически при использовании свойств и методов набора данных клиента. В то же время, при добавлении к интерфейсу своих собственных методов возникает ситуация с прямым вызовом интерфейса. Для этого можно использовать свойство AppServer компонента связи. Например:

MyConnection.AppServer.MyMethod(x,у) ;

Этот способ обеспечивает позднее связывание вызовов интерфейса — связывание, которое происходит только во время исполнения, то есть в момент вызова данного метода. Позднее связывание является очень гибким, но при его использовании теряется много преимуществ, таких как проверка типов и просмотр непосредственно реализации метода. Кроме того, позднее связывание работает более медленно, чем раннее связывание. Это связано с тем, что компилятор генерирует дополнительно вызовы интерфейса на сервер прежде, чем методы вызываются.

Для использования раннего связывания с DCOM, библиотека типов сервера должна быть зарегистрирована на клиентской машине. Для этого надо использовать утилиту TRegsvr.exe, которая распространяется вместе с Delphi.

Для использования раннего связывания с CORBA надо добавить в секцию uses программный модуль, у которого в имени есть расширение _тьв (этот файл генерируется при создании библиотеки типов).

При работе с протоколами TCP/IP или OLEnterprise нельзя использовать раннее связывание, но поскольку удаленный модуль данных использует дуальный интерфейс, можно использовать dispinterface для улучшения производительности (надо также добавить в Uses программный модуль, у которого в имени есть расширение _TLB). Например:

Var Templnterface: IMyAppServerDisp;

begin

Templnterface := MyConnection.AppServer;

Templnterface.SpecialMethod(x,y);

end;

Класс TDispatchConnection

Класс TDispatchConnection является родительским классом для объектов, которые соединяют клиентов с сервером приложений. Он, конечно, не используется напрямую. От него создаются потомки, в которых уже вносится специфика конкретного соединения (рис. 29.2).

Рис. 29.2. Основные компоненты страницы MIDAS

В результате получаем набор компонент связи TDCOMConnection, TSocketConriection, TWebConnection, TCorbaConnection.

TDispatchConnection представляет механизм для вхождения на сервер приложений (проверку имени и пароля пользователя), получения интерфейса IAppserver, вызова интерфейса с сервера, управления удаленным соединением (рис. 29.3).

Рис. 29.3. Основные общие свойства для потомков TDispatchConnection

Основные свойства, которые используются в потомках для обеспечения соединения, отображены в табл. 29.7:

Свойство

Описание

property ServerGUID:

string;

 

 

Определяет QUID сервера приложений, с которым будет осуществляться соединение.

Если указан правильный QUID для зарегистрированного сервера приложений, то автоматически устанавливается и имя класса соответствующего СОМ объекта. Лучше использовать ServerGUID, чем ServerName, так как для него не требуется регистрация на клиенте

property ServerName: string;

Определяет имя сервера приложений, с которым

будет осуществляться соединение.

Если указано правильное имя класса соответствующего объекта, то автоматически устанавливается и QUID сервера приложений

property ObjectBroker:

TCustomObjectBroker; 

 

Определяет брокер объектов, который позволяет

компоненту выбирать один из нескольких серверов приложений. Потомки TDispatchConnection не сохраняют свойства соединения, если указан брокер объектов, потому как он обеспечивает их этой информацией в нужный момент

property Connected: Boolean;

Если значение свойства равно True, то соединение с сервером приложений установлено, и на оборот, если False, то соединение разорвано

Property LoginPrompt: Boolean;

Определяет выводить или нет диалоговое окно

для ввода имени пользователя и пароля перед установлением соединения. Для компонентов MIDAS диалог возникает после события OnGetUserName И Перед событием Befо reconnect

Компонент TDCOMConnection

Протокол DCOM обеспечивает наиболее "прямой" подход к организации связи, не требуя никаких дополнительных приложений во время выполнения на сервере. Однако DCOM не включен в поставку Windows 95, поэтому для этой операционной системы необходимо предварительно его установить.

Компонент используют в клиентской части, и он обеспечивает инициализацию и разрушение соединения, а также обеспечивает работу с интерфейсом IAppServer. С помощью этого компонента устанавливается взаимодействие через протокол DCOM.

Свойства и методы TDCOMConnection представлены в табл. 29.8.

Таблица 29.8. Свойства и методы компонента TDCOMConnection

Объявление

Описание

Property ComputerName: string;

Определяет имя машины, на которой установлен сервер приложении. Если не указать ComputerName, то TDCOMConnection сам определяет местонахождение сервера приложений на основе информации в реестре. Если значение ComputerName определено, то значения соответствующих параметров в реестре переписываются. Обычно клиент и сервер расположены на разных машинах, так что ComputerName должно быть установлено клиентом или прописано в настройках DCOM

Function GetServer: IAppServer; override;

Возвращает интерфейс lAppServer. Набор данных клиента вызывает GetServer для установления своего свойства AppServer. Это позволяет ему иметь доступ к провайдерам на удаленном сервере приложений

Компонент TSocketConnection

Компонент TSocketConnection использует стандартные сокеты Windows для управления соединением с сервером приложений и протокол TCP/IP. Этот компонент может инициировать и прекращать соединение с удаленным сервером приложений, получать интерфейс IAppServer от сервера, а также использовать отдельный СОМ-объект для шифрования содержания сообщений, поддерживать список провайдеров сервера приложений.

В данной реализации MIDAS появилось некоторое изменение в плане безопасности. В прошлом TSocketConnection разрешал выполнять любой объект автоматизации на сервере. Теперь это можно предотвратить, переписав метод UpdateRegistry удаленного модуля данных. В этом методе можно вызвать утилиты, которые отметят сервер приложений как зарегистрированный (более подробное описание утилит см. ниже). Например:

class procedure TMyRDM.UpdateRegistry(Register: Boolean;

const ClassID, ProgID: string) ;

begin

if Register then begin

inherited UpdateRegistry(Register, ClassID, ProgID);

EnableSocketTransport(ClassID) ;

EnableWebTransport(ClassID) ;

end else begin DisabieSocketTransport(ClassID);

DisableWebTransport(ClassID);

inherited UpdateRegistry(Register, ClassID, ProgID);

end;

end;

Еще один параметр для отключения проверки регистрации находится в утилите Scktsrvr.exe.

Свойства и методы TSocketConnection представлены в табл. 29.9.

Таблица 29.9. Свойства и методы компонента TSocketConnection

Свойство

Описание

property Address: String;

Определяет IP-адрес сервера приложений, к которому подсоединяется клиент. Это свойство не обязательно определять, поскольку существует свойство Host, которое можно использовать вместо данного свойства. Эти свойства взаимоисключающие. Либо используется Address, либо — Host.

property Host: String;

Определяет имя хоста сервера приложений, к которому подсоединяется клиент. Как было сказано выше, это свойство взаимоисключающее со свойством Address

property InterceptGUID: string;

Определяет QUID СОМ объекта, который управляет вызовами интерфейса перед отправкой или приемом сообщений. Например, можно использовать свой способ шифрования отправляемых и принимаемых сообщений. Если используется этот дополнительный объект, то сервер должен использовать его же, поэтому в свойствах сервера сокетов (scktSrvr. ехе) надо указать такой же QUID для свойства InterceptGUID

property Port: Integer;

 

 

Определяет номер порта для диспетчера на сервере, который будет использоваться для прослушивания запросов клиента. По умолчанию, это порт номер 211.

Если используется брокер объектов, то нет необходимости указывать значение этого свойства

 Компонент TWebConnection

Компонент TWebConnection использует протокол HTTP для управления соединением с сервером приложений и находится в клиентской части многозвенного приложения. TWebConnection позволяет создавать клиентов, которые могут связываться с сервером приложений через "firewall", используя наиболее распространенный порт для связи. Вместо прямого обращения клиентом к удаленному модулю данных, соединения на основе HTTP используют библиотеку httpsrvr.dll, которая принимает запросы клиента и сама работает с удаленным модулем данных. Web-соединение может воспользоваться преимуществом системы безопасности SSL, обеспечиваемую через библиотеку wininet.dll (эта библиотека используется на клиенте). Благодаря этому можно проверять имя и пароль пользователя через свойства компонента при обращении на сервер приложений. В качестве дополнительной меры защиты, сервер приложений должен регистрировать возможность клиента использовать Web-соединение через вызов EnabiewebTransport в методе UpdateRegislry удаленного модуля данных.

Для Web-соединения можно также организовать пулинг экземпляров.

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

Другая выгода использования протокола HTTP заключается в том, что операционная система, подобная Windows NT, позволяет кластеризовать серверы. Это обеспечивает истинную балансировку нагрузки и отказоустойчивость для сервера приложений.

Этот компонент может устанавливать и прекращать соединение с сервером приложений, получать интерфейс IAppServer от сервера, использовать отдельный СОМ-объект для шифрования содержания сообщений, поддерживать список провайдеров сервера приложений.

Для использования этого компонента необходимо иметь:

Свойства и методы TWebConnection представлены в табл. 29.10.

Таблица 29.10. Свойства и методы компонента TWebConnection

Свойство

Описание

property Password: string;

Определяет пароль, который позволяет клиентскому приложению входить на сервер

property Proxy: string;

Необходимо использовать это свойство, если компонент не может определить имя хоста локально. Если сервер зарегистрирован локально, то значение свойства может быть пустой строкой. С другой стороны, это свойство показывает список всех PROXY-серверов, которые могут перенаправить сообщения клиента на нужный сервер приложений

property URL: string;

Указывает адрес для httpsrvr.dll на сервере

property UserName: string;

Указывает имя пользователя для входа на сервер приложений. Если не требуется проверки, то значение свойства может быть просто пустой строкой

Компонент TCorbaConnection

Протокол CORBA позволяет создавать приложения MIDAS с использованием различных платформ. Используя CORBA, приложение автоматически получает много преимуществ, среди которых — прозрачность расположения, распределение нагрузки и обработка ошибок программным обеспечением ORB. TCorbaConnection используется в клиентской части для установления с помощью CORBA-соединения между клиентом и удаленным сервером приложений.

Свойства и методы TCorbaConnection представлены в табл. 29.11.

Таблица 29.11. Свойства и методы компонента TCorbaConnection

Свойство

Описание

property Cancelable: Boolean;

Позволяет соединениям, которые не смогли быстро установиться, быть отмененными. Когда значение свойства равно True, компонент генерирует отдельный поток для каждого соединения. Если соединению требуется более чем одна секунда для установления, то компонент генерирует событие OnCancel, которое позволяет приложению определять, стоит ли еще ждать или прекратить и повторить после изменения параметров

property HostName: string;

Определяет имя хоста или IP-адрес сервера приложений

Компонент TSimpleObjectBroker

Компонент TSimpleObjectBroker содержит список возможных серверов приложений для компонентов связи. Когда компоненты связи запрашивают сервер, простой брокер объектов передает имя одного из возможных серверов в список. Этот процесс позволяет клиентам определить сервер динамически, во время работы приложения.

TSimpleObjectBroker может случайным образом выбирать сервер среди списка возможных серверов, обеспечивая тем самым некий баланс нагрузки.

Свойства и методы TSimpleObjectBroker представлены в табл. 29.12.

Таблица 29.12. Свойства и методы компонента TSimpleObjectBroker

Свойство

Описание

property LoadBalanced: Boolean;

Определяет, как простой объектный брокер выбирает сервер из списка.

Надо устанавить значение свойства LoadBalanced равным True, чтобы указать, что простой объектный брокер должен снабдить случайным образом именем компьютера из списка, который расположен в свойстве Servers.

Если простой объектный брокер используется компонентами параллельного соединения в клиентском приложении, предпочтительно установить LoadBalanced равным True, чтобы распределить работу среди доступных серверов

property Servers: TServerCollection;

Поддерживает список серверов, которые можно использовать для компонентов связи

property ServerData: OleVariant;

Формирует список серверов как OleVariant.

Чтение ServerData возвращает значение свойства Servers, сохраненного во внутреннем формате Delphi. Запись ServerData устанавливает значение свойства Servers из OleVariant, который был сохранен предварительно

Функции MIDAS

В заключение в этом разделе рассмотрим функции интерфейса MIDAS, играющие вспомогательную роль. Они содержатся в модуле databkr. pas.

Таблица 29.13. Функции интерфейса MIDAS

Метод

Описание

procedure DisableSocketTransport (const ClassID: string) ;

Отменяет регистрацию удаленного модуля данных, после чего клиент не имеет доступа к нему через TSocketConnection. Мастер создания удаленного модуля данных автоматически добавляет вызов DisableSocketTransport в методе UpdateRegistry нового потомка. Это удаляет запись в системном реестре о том, что Scktsrvr. ехе использует проверку, может ли клиент обращаться к серверу приложений. Делает сервер приложений недоступным для клиентов, которые соединяются с ним через TSocketConnection, однако остается доступным для другого типа соединений

procedure DisableWeb-Transport(const ClassID: string);

Отменяет регистрацию удаленного модуля данных, после чего клиент не имеет доступа к нему через TWebConnection. Мастер создания удаленного модуля данных автоматически добавляет вызов DisableWebTransport В методе UpdateRegistry нового потомка. Это удаляет запись в системном реестре о том, что httpsrvr.dll использует проверку, может ли клиент обращаться к серверу приложений. Делает сервер приложений недоступным для клиентов, которые соединяются с ним через TWebConnection, однако остается доступным для другого типа соединений

procedure EnableSock-etTransport(const ClassID: string) ;

Наоборот, добавляет запись, системный реестр и делает доступным для TSocketConnection

procedure EnableWeb-Transport(const ClassID: string) ;

Наоборот, добавляет запись в системный реестр и делает доступным для TWebConnection

procedure Register-Pooled(const ClassID: string; Max, Timeout: Integer; Singleton: Boolean = False);

Служит для организации пула экземпляров удаленного модуля данных, мах указывает максимальное число экземпляров в пуле. Если клиентские приложения запрашивают больше, чем этот максимальный номер, сервер приложений вызывает исключение "Server too busy"

procedure Unregister-Pooled(const ClassID: string);

Служит для прекращения пудинга экземпляров удаленного модуля данных

function PackagePar-ams(Params: TParams; Types: TParamTypes == AllParamTypes): OleVariant;

Преобразовывает объект TParams в OleVariant, который может использоваться в приложениях MIDAS

procedure UnpackPar-ams (const Source: OleVariant; Dest: TParams);

Преобразовывает OleVariant, который представляет набор параметров в объекте TParams

Резюме

Технология MIDAS обеспечивает разработку распределенных многозвенных приложении. При этом используется единый подход для приложений, созданных на основе разных технологий: DCOM, OLEnterprise, MTS, CORBA, сокеты TCP/IP. Все это позволяет создавать огромные корпоративные системы с использованием различных платформ и способов соединения клиентов. Технология MIDAS является одной из наиболее быстро развивающихся технологий, которая имеет широкое применение и по праву занимает одно из первых мест среди ПО промежуточного уровня.