1 сентября 2012 г.

Подключение к серверу приложений

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


Итак, нам необходим удобный способ работы с сервером приложений Лоцман. Основные требования:
  1. Несколько частей приложения или плагина, работающие с разными базами данных и разными рабочими проектами, должны использовать одно подключение к серверу приложений. В первой пробной версии я сделал по одному подключению на каждую базу данных, но выяснилось, что каждое подключение забирает лицензию. Чтобы понапрасну не расходовать дорогие лицензии, должно быть только одно подключение. Из этого следует, что одно подключение должно переключаться между разными базами данных и рабочими проектами, и знать, к какой базе данных оно в настоящее время подключено.
  2. Для экономии лицензий необходимо автоматическое отключения от сервера приложений при длительном простое. При этом использующая подключение часть программы или плагин не должны заботиться о восстановлении подключения. При обращении к серверу приложений, если соединение было разорвано, компонент должен заново подключится к серверу приложений, подключиться к нужной базе данных и рабочему проекту.
  3. Код, использующий подключение к серверу приложений, не должен зависеть от способа соединения с сервером, будь то обычное подключение или вызов метода сервера приложений через интерфейс плагина IPluginCall.
  4. Должна быть возможность создать подключение, отдельное от основного (общего для всех). Например, чтобы подключиться к базе данных от имени другого пользователя, или для того, чтобы использовать подключение в отдельном потоке приложения. Для того, чтобы одинаково работать и с общим подключением, и с отдельными подключениями, необходимо обеспечить автоматический подсчет ссылок на подключение, этого проще всего добиться при использовании интерфейса.
  5. Было бы удобно работать с серверами приложений Лоцман и Workflow через одно подключение, добавляя к имени метода префикс, например WF для методов Workflow. К тому же клиентское приложение Лоцмана обеспечивает такую возможность для плагинов (с версии 10).
Исходя из изложенных выше требований, работа с подключением будет выглядеть примерно так:
var
    LConnection: IRemoteConnection;
    LDataSet: IDataSet;
begin
    LConnection := GetLoodsmanConnection();
    LConnection.CurrentBase := 'Демо_Машиностроение';
    LConnection.CurrentCheckOutID := IdCheckOut;
    LDataSet := LConnection.GetDataSet('GetLinkedFast',
        [IdVersion, 'Состоит из ...', False]);
    ...
end
Интерфейс подключения к серверу приложений:
IRemoteConnection = interface(IInterface)
    ['{0FBADFEF-7975-4C8E-8CC8-7D5323187F5F}']
    function GetDataSet(const AName: String; 
        const AParams: array of Variant): IDataSet;
    function RunMethod(const AName: String; 
        const AParams: array of Variant): Variant;
    property Connected: Boolean read ... write ...;
    property ConnectedWF: Boolean read ... write ...;
    property CurrentBase: String read ... write ...;
    property CurrentCheckOutID: Integer read ... write ...;
    property ServerName: String read ...;
    property ServerVersion: Integer read ...;
end;
Код реализации интерфейса IRemoteConnection достаточно прост, все сложности в нем связаны в основном с тонкостями поддержки одновременно старых и новых версий Лоцмана, в которых существенно изменилась работа с базой Workflow.

При использовании интерфейса IRemoteConnection нужно помнить о том, что он хранит состояние и может подключаться к разным базам данных и рабочим проектам. Поэтому перед вызовом функций сервера приложений необходимо убедиться, что свойства CurrentBase и CurrentCheckOutID установлены в необходимые значения. Например так:
type
    TMyForm = class(TForm)
        procedure BtnOKClick(Sender: TObject);
    private
        FBase: String;
        FCheckOutID: Integer;
        function GetConn: IRemoteConnection;
    protected
        property Base: String read FBase;
        property CheckOutID: Integer read FCheckOutID;
        property Connection: IRemoteConnection read GetConn;
    public
        constructor Create(AOwner: TComponent;
            const ABase: String; ACheckOutID: Integer);
    end;

constructor TMyForm.Create(AOwner: TComponent;
    const ABase: String; ACheckOutID: Integer);
begin
    inherited Create(AOwner);
    FBase := ABase;
    FCheckOutID := ACheckOutID;
end;

function TMyForm.GetConn: IRemoteConnection;
begin
    // Перед тем, как вернуть подключение,
    // его свойства устанавливаются
    // в нужные значения
    Result := GetLoodsmanConnection();
    Result.CurrentBase := FBase;
    Result.CurrentCheckOutID := FCheckOutID;
end;

procedure TMyForm.BtnOKClick(Sender: TObject);
var
    LDataSet: IDataSet;
begin
    // Мы используем подключение, которое
    // соединено с нужной базой данных
    // и рабочим проектом
    LDataSet := Connection.GetDataSet('GetLinkedFast',
        [IdVersion, 'Состоит из ...', False]);
    ...
end;
Основой при создании компонента послужил модуль RemoteConnect.pas, высланный Асконом в примере вызова из автоматической операции WorkFlow функции DLL. Также его код можно найти в файле справки LWFScript_API.chm новых версий Лоцмана. Дополнительные сведения можно почерпнуть из тем форума Выполнение функции напрямую на сервере приложений и Подключение к серверу баз данных.

Код предназначен для Delphi XE. В остальных версиях Delphi могут понадобиться небольшие правки, например убрать {$SCOPEDENUMS ON} и переименовать модули.

Исходный код реализации подключения к серверу приложений

Текущая версия кода на GitHub — github.com/achechulin/loodsman.

Комментариев нет:

Отправить комментарий