home *** CD-ROM | disk | FTP | other *** search
/ Delphi 5 for Professionals / DELPHI5.iso / Runimage / Delphi50 / Demos / Midas / Pooler / pooler.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1999-08-11  |  7.5 KB  |  293 lines

  1. {*******************************************************}
  2. {                                                       }
  3. {        Midas RemoteDataModule Pooler Demo             }
  4. {                                                       }
  5. {*******************************************************}
  6.  
  7. unit Pooler;
  8.  
  9. interface
  10.  
  11. uses
  12.   ComObj, ActiveX, Server_TLB, Classes, SyncObjs, Windows;
  13.  
  14. type
  15. {
  16.   This is the pooler class.  It is responsible for managing the pooled RDMs.
  17.   It implements the same interface as the RDM does, and each call will get an
  18.   unused RDM and use it for the call.
  19. }
  20.   TPooler = class(TAutoObject, IPooledRDM)
  21.   private
  22.     function LockRDM: IPooledRDM;
  23.     procedure UnlockRDM(Value: IPooledRDM);
  24.   protected
  25.     { IAppServer }
  26.     function  AS_ApplyUpdates(const ProviderName: WideString; Delta: OleVariant;
  27.                               MaxErrors: Integer; out ErrorCount: Integer; var OwnerData: OleVariant): OleVariant; safecall;
  28.     function  AS_GetRecords(const ProviderName: WideString; Count: Integer; out RecsOut: Integer;
  29.                             Options: Integer; const CommandText: WideString;
  30.                             var Params: OleVariant; var OwnerData: OleVariant): OleVariant; safecall;
  31.     function  AS_DataRequest(const ProviderName: WideString; Data: OleVariant): OleVariant; safecall;
  32.     function  AS_GetProviderNames: OleVariant; safecall;
  33.     function  AS_GetParams(const ProviderName: WideString; var OwnerData: OleVariant): OleVariant; safecall;
  34.     function  AS_RowRequest(const ProviderName: WideString; Row: OleVariant; RequestType: Integer;
  35.                             var OwnerData: OleVariant): OleVariant; safecall;
  36.     procedure AS_Execute(const ProviderName: WideString; const CommandText: WideString;
  37.                          var Params: OleVariant; var OwnerData: OleVariant); safecall;
  38.   end;
  39.  
  40. {
  41.   The pool manager is responsible for keeping a list of RDMs that are being
  42.   pooled and for giving out unused RDMs.
  43. }
  44.   TPoolManager = class(TObject)
  45.   private
  46.     FRDMList: TList;
  47.     FMaxCount: Integer;
  48.     FTimeout: Integer;
  49.     FCriticalSection: TCriticalSection;
  50.     FSemaphore: THandle;
  51.  
  52.     function GetLock(Index: Integer): Boolean;
  53.     procedure ReleaseLock(Index: Integer; var Value: IPooledRDM);
  54.     function CreateNewInstance: IPooledRDM;
  55.   public
  56.     constructor Create;
  57.     destructor Destroy; override;
  58.     function LockRDM: IPooledRDM;
  59.     procedure UnlockRDM(var Value: IPooledRDM);
  60.  
  61.     property Timeout: Integer read FTimeout;
  62.     property MaxCount: Integer read FMaxCount;
  63.   end;
  64.  
  65.   PRDM = ^TRDM;
  66.   TRDM = record
  67.     Intf: IPooledRDM;
  68.     InUse: Boolean;
  69.   end;
  70.  
  71. var
  72.   PoolManager: TPoolManager;
  73.  
  74. implementation
  75.  
  76. uses ComServ, SrvrDM, SysUtils;
  77.  
  78. constructor TPoolManager.Create;
  79. begin
  80.   FRDMList := TList.Create;
  81.   FCriticalSection := TCriticalSection.Create;
  82.   FTimeout := 5000;
  83.   FMaxCount := 15;
  84.   FSemaphore := CreateSemaphore(nil, FMaxCount, FMaxCount, nil);
  85. end;
  86.  
  87. destructor TPoolManager.Destroy;
  88. var
  89.   i: Integer;
  90. begin
  91.   FCriticalSection.Free;
  92.   for i := 0 to FRDMList.Count - 1 do
  93.   begin
  94.     PRDM(FRDMList[i]).Intf := nil;
  95.     FreeMem(PRDM(FRDMList[i]));
  96.   end;
  97.   FRDMList.Free;
  98.   CloseHandle(FSemaphore);
  99.   inherited Destroy;
  100. end;
  101.  
  102. function TPoolManager.GetLock(Index: Integer): Boolean;
  103. begin
  104.   FCriticalSection.Enter;
  105.   try
  106.     Result := not PRDM(FRDMList[Index]).InUse;
  107.     if Result then
  108.       PRDM(FRDMList[Index]).InUse := True;
  109.   finally
  110.     FCriticalSection.Leave;
  111.   end;
  112. end;
  113.  
  114. procedure TPoolManager.ReleaseLock(Index: Integer; var Value: IPooledRDM);
  115. begin
  116.   FCriticalSection.Enter;
  117.   try
  118.     PRDM(FRDMList[Index]).InUse := False;
  119.     Value := nil;
  120.     ReleaseSemaphore(FSemaphore, 1, nil);
  121.   finally
  122.     FCriticalSection.Leave;
  123.   end;
  124. end;
  125.  
  126. function TPoolManager.CreateNewInstance: IPooledRDM;
  127. var
  128.   p: PRDM;
  129. begin
  130.   FCriticalSection.Enter;
  131.   try
  132.     New(p);
  133.     p.Intf := RDMFactory.CreateComObject(nil) as IPooledRDM;
  134.     p.InUse := True;
  135.     FRDMList.Add(p);
  136.     Result := p.Intf;
  137.   finally
  138.     FCriticalSection.Leave;
  139.   end;
  140. end;
  141.  
  142. function TPoolManager.LockRDM: IPooledRDM;
  143. var
  144.   i: Integer;
  145. begin
  146.   Result := nil;
  147.   if WaitForSingleObject(FSemaphore, Timeout) = WAIT_FAILED then
  148.     raise Exception.Create('Server too busy');
  149.   for i := 0 to FRDMList.Count - 1 do
  150.   begin
  151.     if GetLock(i) then
  152.     begin
  153.       Result := PRDM(FRDMList[i]).Intf;
  154.       Exit;
  155.     end;
  156.   end;
  157.   if FRDMList.Count < MaxCount then
  158.     Result := CreateNewInstance;
  159.   if Result = nil then { This shouldn't happen because of the sempahore locks }
  160.     raise Exception.Create('Unable to lock RDM');
  161. end;
  162.  
  163. procedure TPoolManager.UnlockRDM(var Value: IPooledRDM);
  164. var
  165.   i: Integer;
  166. begin
  167.   for i := 0 to FRDMList.Count - 1 do
  168.   begin
  169.     if Value = PRDM(FRDMList[i]).Intf then
  170.     begin
  171.       ReleaseLock(i, Value);
  172.       break;
  173.     end;
  174.   end;
  175. end;
  176.  
  177. {
  178.   Each call for the server is wrapped in a call to retrieve the RDM, and then
  179.   when it is finished it releases the RDM.
  180. }
  181.  
  182. function TPooler.LockRDM: IPooledRDM;
  183. begin
  184.   Result := PoolManager.LockRDM;
  185. end;
  186.  
  187. procedure TPooler.UnlockRDM(Value: IPooledRDM);
  188. begin
  189.   PoolManager.UnlockRDM(Value);
  190. end;
  191.  
  192. function TPooler.AS_ApplyUpdates(const ProviderName: WideString;
  193.   Delta: OleVariant; MaxErrors: Integer; out ErrorCount: Integer;
  194.   var OwnerData: OleVariant): OleVariant;
  195. var
  196.   RDM: IPooledRDM;
  197. begin
  198.   RDM := LockRDM;
  199.   try
  200.     Result := RDM.AS_ApplyUpdates(ProviderName, Delta, MaxErrors, ErrorCount, OwnerData);
  201.   finally
  202.     UnlockRDM(RDM);
  203.   end;
  204. end;
  205.  
  206. function TPooler.AS_DataRequest(const ProviderName: WideString;
  207.   Data: OleVariant): OleVariant;
  208. var
  209.   RDM: IPooledRDM;
  210. begin
  211.   RDM := LockRDM;
  212.   try
  213.     Result := RDM.AS_DataRequest(ProviderName, Data);
  214.   finally
  215.     UnlockRDM(RDM);
  216.   end;
  217. end;
  218.  
  219. procedure TPooler.AS_Execute(const ProviderName, CommandText: WideString;
  220.   var Params, OwnerData: OleVariant);
  221. var
  222.   RDM: IPooledRDM;
  223. begin
  224.   RDM := LockRDM;
  225.   try
  226.     RDM.AS_Execute(ProviderName, CommandText, Params, OwnerData);
  227.   finally
  228.     UnlockRDM(RDM);
  229.   end;
  230. end;
  231.  
  232. function TPooler.AS_GetParams(const ProviderName: WideString;
  233.   var OwnerData: OleVariant): OleVariant;
  234. var
  235.   RDM: IPooledRDM;
  236. begin
  237.   RDM := LockRDM;
  238.   try
  239.     Result := RDM.AS_GetParams(ProviderName, OwnerData);
  240.   finally
  241.     UnlockRDM(RDM);
  242.   end;
  243. end;
  244.  
  245. function TPooler.AS_GetProviderNames: OleVariant;
  246. var
  247.   RDM: IPooledRDM;
  248. begin
  249.   RDM := LockRDM;
  250.   try
  251.     Result := RDM.AS_GetProviderNames;
  252.   finally
  253.     UnlockRDM(RDM);
  254.   end;
  255. end;
  256.  
  257. function TPooler.AS_GetRecords(const ProviderName: WideString;
  258.   Count: Integer; out RecsOut: Integer; Options: Integer;
  259.   const CommandText: WideString; var Params,
  260.   OwnerData: OleVariant): OleVariant;
  261. var
  262.   RDM: IPooledRDM;
  263. begin
  264.   RDM := LockRDM;
  265.   try
  266.     Result := RDM.AS_GetRecords(ProviderName, Count, RecsOut, Options,
  267.       CommandText, Params, OwnerData);
  268.   finally
  269.     UnlockRDM(RDM);
  270.   end;
  271. end;
  272.  
  273. function TPooler.AS_RowRequest(const ProviderName: WideString;
  274.   Row: OleVariant; RequestType: Integer;
  275.   var OwnerData: OleVariant): OleVariant;
  276. var
  277.   RDM: IPooledRDM;
  278. begin
  279.   RDM := LockRDM;
  280.   try
  281.     Result := RDM.AS_RowRequest(ProviderName, Row, RequestType, OwnerData);
  282.   finally
  283.     UnlockRDM(RDM);
  284.   end;
  285. end;
  286.  
  287. initialization
  288.   PoolManager := TPoolManager.Create;
  289.   TAutoObjectFactory.Create(ComServer, TPooler, Class_Pooler, ciMultiInstance, tmFree);
  290. finalization
  291.   PoolManager.Free;
  292. end.
  293.