Создание CORBA-сервера

Усложним задачу, добавив в проект новый сервер для CORBA-соединения. Его создание как две капли воды похоже на изготовление обычного сервера, о чем мы только что говорили. Вся разница состоит лишь в том, что на начальном этапе вместо мастера Remote Data Module мы запускаем мастер New?Multitier?CORBA Data Module. Компоненты доступа к данным и их связывание точно такое же. Модуль формы сервера сохраните как CORBAMain.pas, имя формы (свойство Caption) установите как MsgForm, ее заголовок (свойство Caption) — «Client Messages», а сам проект должен быть сохранен как CORBA_RDM_ Server.dpr. Точно так же в форму нужно положить компонент TProgressBar. Не забудьте включить опцию проекта Build with runtime packages.

Теперь о различиях. Они проявятся, как только вы запустите мастер CORBA Data Module. Поле Class Name вам уже знакомо, в него следует ввести имя CORBA_RDM. Зато ранее мы не сталкивались с полями Instancing и Threading Model. Если вы хотите, чтобы для каждого клиентского вызова создавался новый экземпляр удаленного модуля данных, следует установить в поле Instancing опцию Instance-per-client. Если установить опцию Shared Instance, один экземпляр модуля будет обслуживать запросы от разных клиентов (то, что нужно нам). В поле Threading Model нужно указывать, должен ли модуль обслуживать несколько вызовов одновременно (Multithreaded) или по одному вызову за раз (Single-threaded), что мы с вами и сделаем.

Сохраним исходный текст в файле с именем CORBA_RDM_Impl.pas и откомпилируем проект. В отличие от обычного удаленного модуля данных, аналогичный модуль на основе CORBA не требует регистрации. Если же вы хотите автоматически запускать подобный CORBA-сервер, то следует обратиться к документации по Inprise VisiBroker к разделу, посвященному OAD.

Исходные тексты CORBA-сервера приведены в листинге 1.

Листинг 1

CORBA-сервер

Файл CORBA_RDM_Impl.dfm
object CORBA_RDM: TCORBA_RDM
  OldCreateOrder = False
  Left = 65
  Top = 197
  Height = 480
  Width = 696
  object DataSetProvider1: TDataSetProvider
    DataSet = IBQuery1
    Constraints = True
    AfterGetRecords = 
DataSetProvider1AfterGetRecords
    Left = 45
    Top = 20
  end
  object IBDatabase1: TIBDatabase
    Connected = True
    DatabaseName = ?
D:BorlandInterbaseexamplesdatabase
Employee.gdb?
    Params.Strings = (
      ?user_name=SYSDBA?
      ?password=masterkey?)
    LoginPrompt = False
    DefaultTransaction = IBTransaction1
    IdleTimer = 0
    SQLDialect = 1
    TraceFlags = []
    Left = 45
    Top = 105
  end
  object IBTransaction1: TIBTransaction
    Active = True
    DefaultDatabase = IBDatabase1
    Left = 165
    Top = 110
  end
  object IBQuery1: TIBQuery
    Database = IBDatabase1
    Transaction = IBTransaction1
    Active = True
    CachedUpdates = False
    SQL.Strings = (
      
 ?select CUST_NO, SALES_REP, ORDER_DATE, PAID,
QTY_ORDERED, TOTAL_? +
        ?VALUE from SALES?)
    Left = 45
    Top = 200
    object IBQuery1CUST_NO: TIntegerField
      FieldName = ?CUST_NO?
      Required = True
    end
    object IBQuery1SALES_REP: TSmallintField
      FieldName = ?SALES_REP?
    end
    object IBQuery1ORDER_DATE: TDateTimeField
      FieldName = ?ORDER_DATE?
      Required = True
    end
    object IBQuery1PAID: TIBStringField
      FieldName = ?PAID?
      Size = 1
    end
    object IBQuery1QTY_ORDERED: TIntegerField
      FieldName = ?QTY_ORDERED?
      Required = True
    end
  end
end

Файл CORBA_RDM_Impl.pas
unit CORBA_RDM_Impl;

interface

uses
  Windows, Messages, SysUtils, Classes, 
 Graphics, Controls,
Forms, Dialogs,
  ComObj, VCLCom, StdVcl, DataBkr, 
 CorbaRdm, CorbaObj,
  CORBA_Server_TLB, Db, IBCustomDataSet, 
 IBQuery, IBDatabase
 Provider,
  CORBAMain;

type

TCORBA_RDM = class(TCorbaDataModule, 
ICORBA_RDM)
    DataSetProvider1: TDataSetProvider;
    IBDatabase1: TIBDatabase;
    IBTransaction1: TIBTransaction;
    IBQuery1: TIBQuery;
    IBQuery1CUST_NO: TIntegerField;
    IBQuery1SALES_REP: TSmallintField;
    IBQuery1ORDER_DATE: TDateTimeField;
    IBQuery1PAID: TIBStringField;
    IBQuery1QTY_ORDERED: TIntegerField;
    procedure 
DataSetProvider1AfterGetRecords(Sender: 
TObject;
      var OwnerData: OleVariant);
  private
    { Private declarations }
  public
    { Public declarations }
  protected
    { Protected declarations }
  end;

var
  CORBA_RDM: TCORBA_RDM;

implementation

{$R *.DFM}

uses CorbInit, CorbaVcl;

procedure TCORBA_RDM
.DataSetProvider1AfterGetRecords(Sender:
TObject;
  var OwnerData: OleVariant);
begin
  with MsgForm.ProgressBar1 do
  begin
    If Position < Max then
      StepIt
    else
      Position := 0;
    end;
end;

initialization
  TCorbaVclComponentFactory
 .Create(?CORBA_RDMFactory?,
?CORBA_RDM?, ?IDL:CORBA_Server
/CORBA_RDMFactory:1.0?,
ICORBA_RDM,
    TCORBA_RDM, iSingleInstance, 
	tmSingleThread);
end.

Создание клиента

Наконец мы добрались до кульминационного момента — создания программы-клиента (исходные тексты приведены в листинге 2).

Создадим новый проект и, как обычно, включим опцию проекта Build with runtime packages. Проект сохраним под именем Client.dpr, а главное окно программы будет носить имя ClientForm. Модуль окна сохраняется в файле ClientFormUnit.pas.

Интерфейс пользователя сделать несложно: поместим в главную форму компонент TCoolBar и установим его свойство AutoSize в значение True. Внутрь TCoolBar поместим компоненты TDBNavigator (для перемещения по данным) и TComboBox (для переключения между различными типами соединений). В раскрывающемся списке отредактируем свойство Items, определяющее пункты выбора. Таких пунктов должно быть три: DCOMConnection, SocketConnection и CorbaConnection.

В соответствии с традицией все компоненты, заведующие работой с данными, следует вынести в отдельный модуль. Поэтому командой New...?New? Data Module создадим подобный модуль данных и сохраним его под именем ClientDM, его свойство Name установим как dm. Внутрь полученного модуля кладутся следующие компоненты: TClientDataSet, TDataSource, TsocketConnection, TDCOMConnection и TCorbaConnection. Настройка первого из них очень проста. Его свойство ProviderName должно указывать на компонент DataSetProvider1. Еще важно, чтобы свойству Active было присвоено False, т. е. клиент должен быть отключен от сервера. Компонент TDataSource своим свойством DataSet будет указывать на TClientDataSet.

Теперь поработаем с компонентами соединения. TDCOMConnection будет носить имя DCOMGate, а его свойство ComputerName однозначно определяет имя компьютера, где запущен сервер MIDAS-приложения. Так же подстраиваем свойство ServerName. Delphi сам предложит для него правильное значение. Свойство Connected устанавливается в отключенное положение (должно быть False). Аналогично производится настройка TSocketConnection, только его имя будет SocketGate, а вместо свойства ComputerName настраивается Host.

С компонентом TCorbaConnection возни чуть больше. Для его корректного функционирования нужно присвоить свойству RepositaryId правильное значение, ссылающееся на удаленный модуль CORBA. Его можно найти в исходных текстах удаленного модуля данных CORBA_RDM. Разыщите строчку с вызовом TCorbaVclComponentFactory.Create(). Его третий параметр и будет правильным значением для RepositaryId.

Остается подстроить свойство DataSource компонентов TDBNavigator и TDBGrig так, чтобы оно указывало на dm.DataSource1, и откомпилировать проект.

Исходные тексты программы-клиента вы найдете в листинге 2.

Листинг 2

Программа-клиент

Файл ClientFormUnit.dfm
object ClientForm: TClientForm
  Left = 143
  Top = 192
  Width = 632
  Height = 381
  Caption = ?Universal MIDAS Client?
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -13
  Font.Name = ?MS Sans Serif?
  Font.Style = []
  OldCreateOrder = False
  OnShow = FormShow
  PixelsPerInch = 120
  TextHeight = 16
  object CoolBar1: TCoolBar
    Left = 0
    Top = 0
    Width = 624
    Height = 29
    AutoSize = True
    Bands = <
      item
        Control = DBNavigator1
        ImageIndex = -1
        Width = 273
      end
      item
        Break = False
        Control = ComboBox1
        ImageIndex = -1
        MinHeight = 24
        Width = 345
      end>
    object ComboBox1: TComboBox
      Left = 284
      Top = 0
      Width = 332
      Height = 24
      Style = csDropDownList
      ItemHeight = 16
      TabOrder = 0
      OnChange = ComboBox1Change
      Items.Strings = (
        ?DCOMConnection?
        ?SocketConnection?
        ?CorbaConnection?)
    end
    object DBNavigator1: TDBNavigator
      Left = 9
      Top = 0
      Width = 260
      Height = 25
      DataSource = dm.DataSource1
      TabOrder = 1
    end
  end
  object DBGrid1: TDBGrid
    Left = 0
    Top = 29
    Width = 624
    Height = 320
    Align = alClient
    DataSource = dm.DataSource1
    TabOrder = 1
    TitleFont.Charset = DEFAULT_CHARSET
    TitleFont.Color = clWindowText
    TitleFont.Height = -13
    TitleFont.Name = ?MS Sans Serif?
    TitleFont.Style = []
  end
end

Файл ClientDM.dfm
object dm: Tdm
  OldCreateOrder = False
  Left = 58
  Top = 179
  Height = 480
  Width = 696
  object DCOMGate: TDCOMConnection
    ServerGUID = 
?{CEFB8363-867D-11D3-9531-008048DEAFF9}?
    ServerName = ?RDM_Server.RDM?
    ComputerName = ?Dimos?
    Left = 55
    Top = 10
  end
  object SocketGate: TSocketConnection
    ServerGUID = 
?{CEFB8363-867D-11D3-9531-008048DEAFF9}?
    ServerName = ?RDM_Server.RDM?
    Host = ?Dimos?
    Left = 145
    Top = 10
  end
  object CorbaGate: TCorbaConnection
  RepositoryId = ?CORBA_Server/CORBA_RDM?
  Left = 230
  Top = 10
  end
  object DataSource1: TDataSource
    DataSet = ClientDataSet1
    Left = 55
    Top = 150
  end
  object ClientDataSet1: TClientDataSet
    Aggregates = <>
    Params = <>
    ProviderName = ?DataSetProvider1?
    Left = 55
    Top = 85
  end
end
Файл ClientFormUnit.pas
unit ClientFormUnit;

interface

uses
  Windows, Messages, SysUtils, 
Classes, Graphics, Controls,
Forms, Dialogs,
  ExtCtrls, DBCtrls, StdCtrls, 
ToolWin, ComCtrls, Grids,
DBGrids, ClientDM,
  DBClient;

type
  TClientForm = class(TForm)
    CoolBar1: TCoolBar;
    ComboBox1: TComboBox;
    DBNavigator1: TDBNavigator;
    DBGrid1: TDBGrid;
    procedure ComboBox1Change(Sender: 
TObject);
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure Reconnect;
  end;

var
  ClientForm: TClientForm;
  LastConnection: Integer;
  Connections: array[0..2] of 
^TCustomRemoteServer;

implementation

{$R *.DFM}

procedure TClientForm
.ComboBox1Change(Sender: TObject);
begin
  if LastConnection <> ComboBox1
.ItemIndex then Reconnect;
end;

procedure TClientForm.Reconnect;
begin
  // Отключиться от удаленного сервера
  Connections[LastConnection].Connected 
:= False;
  LastConnection := ComboBox1.ItemIndex;
  // Подключиться к удаленному серверу
  dm.ClientDataSet1.Close;
  dm.ClientDataSet1.RemoteServer
:= Connections
[LastConnection]^;
  dm.ClientDataSet1.Open;
  Connections[LastConnection].Connected 
:= True;
  dm.ClientDataSet1.Refresh;
  // Показать тип соединения
  ComboBox1.ItemIndex := LastConnection;
end;

procedure TClientForm.FormShow(Sender
: TObject);
begin
  // Заполнить массив указателей на 
компоненты соединения
  Connections[0] := @dm.DCOMGate;
  Connections[1] := @dm.SocketGate;
  Connections[2] := @dm.CorbaGate;
  // Установить индекс соединения на DCOM
  LastConnection := 0;
  ComboBox1.ItemIndex := LastConnection;
  Reconnect;
end;
end. 

Как запустить MIDAS-приложение

Для обеспечения работы систем, выполненных по технологии MIDAS, могут потребоваться дополнительные утилиты. Так, чтобы стало действовать соединение на основе CORBA, следует активизировать программу Smart Agent из пакета VisiBroker. Соединение через сокеты установится после запуска SCKTSRVR.EXE каталога BIN пакета Delphi. Дополнительных действий не требует лишь соединение по протоколу DCOM.

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

Рис. 1

*  *  *

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