"Use of Visibroker for Delphi" (3)
-CORBA technology practice (1)
Yichang City Center People's Hospital Zhao Pu
Email: 3boy@sohu.com
3, array object to pass the simple data object
The previous mentioned some simple data operations, we can imagine, if the CORBA object is the same as the data object of the operation C / S structure, then CORBA is magical, don't know how to read Li Wei's distribution When you have a book of multi-storey application, do you pay attention to Li Wei's evaluation of CORBA, no matter what you have seen
Still haven't seen, I have to tell the friends who are using CORBA programming, CORBA is simpler than COM / COM , and CORBA's cross-platform feature, and the same load balance with COM / COM , it is enough to let us distribute this Technology is applied to the design of the application system, in fact, for the use of Borland's product development, no matter whether you use CORBA or COM / COM , the most core technology is Midas because
You can always see the shadow of Midas in CORBA / COM / COM , so I suggest that you are ready to learn CORBA or learn COM / COM , it is best to learn MIDAS, this article does not involve Midas, about Midas, please see Li Wei's " Delphi5.x Distributed Multi-Layer Application - Systems ".
Why do I have always written IDL from the beginning of the text editor, not Typelibrary
To write IDL, in fact, I think it is just to get some more IDL knowledge to get programmers who have just contacted CORBA. In actual development, you can use TypeLibrary to write interface rules in actual development.
Below I am briefly listing the examples written by several IDLs and the PASCAL code generated using the IDL2PAS.
1, the definition of constant
/ ** IDL writing ** /
Module mycrb {
Const long iMyconst = 1;
Interface myface {
Const long iimyconst = 2;
}
}
/ ** pascal ** /
Unit mycrb_i;
Interface
Uses corba;
Const
iMyconst: integer = 1;
myface_iimyconst = 2;
2,) constant in the interface
/ ** id1 ** /
Module mycrb {
Const long myconst = 1;
}
/ * pascal * /
Unit mycrb_i;
Interface
Const myconst: integer = 1;
3, enumerated type
/ * Id1 * /
Enum mycrbkind {a, b, c, d, ...... ..
/ * pascal * /
Mycrbkind = (A, B, C, D ... ..);
4,) structure
/ * Id1 * /
Struct myStructType {
Long x;
String y;
Boolean Z;
}
/ * pascal * /
//Xxx_i.pas
TYPE mYStructType = interface;
//Xxx_c.pas
MyStructType = Interface
Function _get_x: integer;
Function _get_y: string;
Function _get_z: bolean;
Procedure_set_x (const value: integer);
Procedure_set_y (const value: string);
Procedure_Set_z (Const Value: Boolean);
Property X: Integer Read_Get_x Write_Set_x; Property Y: String Read_Get_y Write_Set_y;
Property Z: Boolean Read_Get_z Write_Set_z;
.......
There are too many code, create a look, don't make a detailed translation in order to save the space.
Let's try the following PASCAL code for the following buds.
5, the uniform
Union UN_EXP Switch (long)
{
Case 1: long x;
Case 2: String Y;
Case 3: ST_EXP Z;
}
6, SEQUENCE (I understand as a dynamic array)
Typedef sequern
Typedef Sequence
7, array
Const long arraybound = 10;
Typedef long longaray [arraybound];
8, abstract interface
Module Exp {
Interface myface {
Long OP (in string s);
}
}
9, multiple inheritance
Module M {
Interface a {
Void A1 ();
Void A2 ();
}
Interface b {
Void B1 ();
Void B2 ();
}
Interface AB: B, A {
Void AB1 ()
Void ab2 ();
}
}
10, cross-model definition
Module m1 {
Interface IF1;
Module M2 {
Interface if2 {
M1 :: if1 getif1 ();
}
Interface if1 {
M2 :: if2 getif2 ()
}
}
}
I introduced some of the definition specifications for data, but we need not only such a more abstract interface definition rule. We must apply the law to the actual development, then we use these laws, for the interface Description Language Translated I speaking directly using IDL2PAS, I don't talk about how to convert it in the following chapters. Below we practice:
Writing Interface Defines a method of returning to floating point types, entered as a short-intensive variable array object
Typedef Short ArrayType [3];
// Customize the array of length 3
Interface account {
Float InputArray (In ArrayType MyArray); / / Enter a plastic array, return type FLOAT method
}
// Service server processing XXX_IMPL.PAS
Interface
Uses
SYSUTILS,
Corba,
Account_i,
Account_c;
Type
Taccount = Class;
Taccount = Class (TinterFaceDObject, Account_i.account)
protected
// ******************
public
Constructor crete;
Function INPUTARRAY (const myarray): Single;
END;
IMPLEMENTATION
Uses ServerMain;
Constructor taccount.create;
Begin
inherited;
END;
Function Taccount. INPUTARRAY (const myarray): Single;
VAR
J: integer;
Begin
// Account_i.ArrayType refers to our custom array type in the Account_i unit for J: = 0 to 2 DO
Begin
Form1.Memo1.Lines.Add ('MyArray [ INTSTOSTR (J) '] = ' INTOSTR (MyArray [J]));
/ / Accept the array variable passed from the client and sequentially add it to the main form of MEMO
END;
Result: = random * 100; // Return a random number
END;
INITIALIZATION
Randomize;
End.
// Service server main unit
UNIT ServerMain;
Interface
Uses
Windows, Messages, Sysutils, Classes, Graphics, Controls, Forms, Dialogs, CORBA,
Account_i, Account_c, Account_s, Account_Impl, Stdctrls;
Type
TFORM1 = Class (TFORM)
Memo1: TMEMO;
Procedure formcreate (Sender: TOBJECT);
Private
{Private Declarations}
protected
{Protected Declarations}
Acct: account; // skellon object
Procedure Initcorba;
public
{public declarations}
END;
VAR
FORM1: TFORM1;
IMPLEMENTATION
{$ R * .dfm}
Procedure TFORM1.INITCORBA;
Begin
Corbainitialize;
// Add Corba Server Code Here
Acct: = Taccountskeleton.create ('Array Server', Taccount.create);
Boa.objisready (ACCT AS _OBJECT);
END;
Procedure TFORM1.FormCreate (Sender: TOBJECT);
Begin
Initcorba;
Memo1.Lines.Add ('Account Object Created ...');
Memo1.Lines.Add ('Server Is Ready');
END;
End.
/ / Client program
Unit clientmain;
Interface
Uses
Windows, Messages, Sysutils, Classes, Graphics, Controls, Forms, Dialogs,
Corba, stdctrls, account_i, account_c;
Type
TFORM1 = Class (TFORM)
Button1: tbutton;
Label1: TLABEL;
Procedure formcreate (Sender: TOBJECT);
Procedure Button1Click (Sender: TOBJECT);
Private
{Private Declarations}
protected
{Protected Declarations}
Acct: Account;
MyArray: ArrayType;
Procedure Initcorba;
public
{public declarations}
END;
VAR
FORM1: TFORM1;
IMPLEMENTATION
{$ R * .dfm}
Procedure TFORM1.INITCORBA;
Begincorbainitialize;
Acct: = taccounthelper.bind;
END;
Procedure TFORM1.FormCreate (Sender: TOBJECT);
VAR
J: integer;
Begin
Initcorba;
For j: = 0 to 2 do
MyArray [J]: = (J 1) * 100;
END;
Procedure TFORM1.BUTTON1CLICK (Sender: TOBJECT);
Begin
Label1.caption: = formatfloat ('INPUTARRAY = $ #, ## 0.00', acct.inputArray (MyArray);
END;
End.
The above program instance is very simple, I will not explain, let's take a look at an instance of a data access.
// idl
Interface Employee {
Any getEmployeesbyName (in string name);
}
Interface method declaration unit
//Xxx_impl.pas
Interface
Uses
SYSUTILS,
Corba,
EMPLOYEE_I,
EMPLOYEE_C;
Type
Temployee = Class;
Temployee = Class (TinterFaceDObject, Employee_i.employee)
public
Constructor crete;
Function geTemployeesbyName (const name): Any;
END;
IMPLEMENTATION
Uses DMemPloyee, Dmpooler, Provider, DSINTF, ServerMain
Constructor temploye.create;
Begin
inherited;
END;
Function Temployee.GeTemPloyeesbyName (const name: ansistring): Any;
VAR
DM: TDMEMPLOY;
RECSOUT: Integer;
Options: TgetRecordOptions;
Begin
Options: = [grmetadata, grreset]; // Must Specify Meta Data
DM: = modulepooler.getModule As TdMemploy; // Get Instance of DataModule from pool
Try
DM.QRYEMPLOYE.CLOSE;
DM.QRYEMPLOYEE.PARAMBYNAME ('Name'). Asstring: = name '%';
// Display the number of connected servers
INC (Form1.hitcount);
Form1.label1.caption: = format ('hit count =% d', [form1.hitcount]);
DM.QRYEMPLOYE.OPEN
Result: = dm.proemployee.getRecords (-1, recsout, byte (options));
DM.QRYEMPLOYE.CLOSE;
Finally
ModulePooler.FreeModule (DM); // Return Instance of DataModule To Pool
END;
END;
INITIALIZATION
// put the TDMemPloy object into the shared pool
ModulePooler.ModuleClass: = TDMEMPLOY;
End.
// Mean of shared pool
Mainly describes how to provide a multi-customer access data to provide Unit Dmpooler;
Interface
Uses Sysutils, Classes, Forms, Syncobjs, Windows
Type
// This unit is used to provide a separate DataModule object for each customer, equivalent to the same functionality as we choose to create in the previous CORBA DATAMODULE.
TDataModuleClass = Class of TdataModule; // Defining class
TPOOLEDMODULE = Record // Declaration Record Type
Module: tdataModule; // Inherited standard TDATAMODULE
Inuse: boolean; / / indicate whether TDATAMODULE is inherited above
END;
TMODULEPOOLER = Class
Private
FCsect: tcriticalsection; // Allow threads to change FModules yourself
FmoduleClass: TDataModuleclass; // Medium TDATAModule in shared pool
FModules: array of tpooledModule; / / Define a dynamic object record array
FSEMAPHORE: THANDLE; / / Limit the user rules for simultaneous use
public
Property ModuleClass: TDataModuleclass Read FmoduleClass Write Fmoduleclass;
Constructor crete;
DESTRUCTOR DESTROY; OVERRIDE;
Function getModule: TDATAModule;
Procedure FreeModule (DATAModule: tdataModule);
END;
Const
Poolsize = 5;
VAR
ModulePooler: TModulePooler = NIL;
IMPLEMENTATION
Uses dialogs;
{TMODULEPOOL}
Constructor TModulePooler.create;
Begin
Ismultithread: = true;
FCsect: = TcriticalSection.create;
FSemaphore: = CreateSemaphore (NIL, PoolSize, Poolsize, NIL);
END;
DESTRUCTOR TMODULEPOOLER.DESTROY;
Begin
Fcsect.free;
CloseHandle (FSEMAPHORE);
END;
Procedure TModulePooler.FreeModule (DATAModule: TDataModule);
VAR
I: integer;
Begin
Fcsect.enter;
Try
For i: = 0 to Length (FModules) - 1 DO
IF fmodules [i] .Module = DATAMODULE THEN
Fmodules [i] .inuse: = false;
ReleaseSemaphore (FSemaphore, 1, NIL);
Finally
Fcsect.Leave;
END;
END;
Function TModulePooler.getModule: TDATAMODULE;
VAR
I: integer;
Begin
Result: = NIL;
IF WaitforsingleObject (fsemaphore, 5000) = Wait_timeout then
Raise Exception.create ('Server Too Bussy');
FCsect.Enter; Try
if Length (FModules) = 0 THEN
Begin
SETLENGTH (FModules, poolsize);
For i: = 0 to poolsize - 1 do
Begin
Fmodules [i] .inuse: = false;
FModules [i] .Module: = fmoduleclass.create (Application);
END;
END;
For i: = 0 to Length (FModules) - 1 DO
IF not fModules [i] .inuse kil
Begin
Fmodules [i] .inuse: = true;
Result: = fmodules [i] .Module
Break;
END;
Finally
Fcsect.Leave;
END;
/ / Check if it is connected
IF not assigned (result) THEN
Raise Exception.create ('Pool Is Out of Capacity');
END;
INITIALIZATION
ModulePooler: = TModulePooler.create;
Finalization
ModulePooler.Free;
End.
// This unit is a universal method unit, of course, you can also use other methods to complete such a function.
// DataModule unit
Unit DMemPloyee;
Interface
Uses
Windows, Messages, Sysutils, Classes, Graphics, Controls, Forms, Dialogs,
DB, DBTABLES, Provider;
Type
TDMEMPLOY = Class (TDATAModule)
SESSION1: TSESSION;
Employeedatabase: TDATABASE;
QRYEMPLOYEE: TQuery;
ProEmployee: TDataSetProvider;
Private
{Private Declarations}
public
{Public declarations}
END;
VAR
DMemploy: TDMEMPLOY;
IMPLEMENTATION
{$ R * .dfm}
End.
// server main unit
UNIT ServerMain;
Interface
Uses
Windows, Messages, Sysutils, Classes, Graphics, Controls, Forms, Dialogs,
Grids, DBGRIDS, DB, DBTABLES, STDCTRLS, CORBA, EMPLOYE_I, EMPLOYEE_C,
Employee_s, EmployeE_Impl;
Type
TFORM1 = Class (TFORM)
Label1: TLABEL;
Procedure formcreate (Sender: TOBJECT);
Private
{Private Declarations}
Procedure Corbainit;
public
{Public declarations}
Hitcount: integer;
END;
VAR
FORM1: TFORM1;
MYDBSERVER: Employee;
IMPLEMENTATION
{$ R * .dfm}
Procedure TFORM1.CORBAINIT;
Begin
Corbainitialize;
Mydbserver: = Temployeeskeleton.create ('MyServer', Temploye.create); Boa.objisready (MyDBServer As _Object);
END;
Procedure TFORM1.FormCreate (Sender: TOBJECT);
Begin
Corbainit;
END;
End.
/ / Client program
Interface
Uses
Windows, Messages, Sysutils, Classes, Graphics, Controls, Forms, Dialogs,
Stdctrls, Grids, Corba, Employee_i, Employee_c, DB, DBCLIENT, EXTCTRLS,
DBCTRLS, DBGRIDS;
Type
TFORM1 = Class (TFORM)
Button1: tbutton;
DBGRID1: TDBGRID;
CDSemPloyee: TclientDataSet;
DataSource1: TDataSource;
Edtemployeename: tedit;
Memo1: TMEMO;
Label1: TLABEL;
Procedure formcreate (Sender: TOBJECT);
Procedure Button1Click (Sender: TOBJECT);
Private
{Private Declarations}
myemployee: Employee;
public
{Public declarations}
END;
VAR
FORM1: TFORM1;
IMPLEMENTATION
{$ R * .dfm}
Procedure TFORM1.FormCreate (Sender: TOBJECT);
Begin
MyEmployee: = TemployeeHelper.bind;
END;
Procedure TFORM1.BUTTON1CLICK (Sender: TOBJECT);
Begin
CDSemPloyee.Data: = myemployee.getemployeesbyname (edTemPloyeename.Text);
CDSemPloye.Open;
END;
End.
I think everyone should understand the above program. If you don't understand it, don't matter, the next time I will launch a series of problems around this example and compare the same time in COM / MIDAS, in order to let everyone leave a thinking I haven't said it here. Still the next time next time
My philosophy: "Whether it is CORBA or COM vast or EJB, etc.