unit uAppCenter;

{$WARN SYMBOL_PLATFORM OFF}

interface

uses
Windows, ComObj, ComServ, ActiveX, HISAPP_TLB, Classes, SyncObjs, StdVcl,
VCLCom, SysUtils, Forms, uDataType;

type
TAppCenter = class(TComponent, IRDMSystem)
private
    function LockRDM: IRDMSystem;
    procedure UnlockRDM(Value: IRDMSystem);
protected
    { 实现IAppServer接口定义的方法 }
    function AS_ApplyUpdates(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; Data: OleVariant): OleVariant; safecall;
    function AS_GetProviderNames: 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;
                         
    { 实现IDMSystem接口定义的方法 }
    // 用户登录函数
    procedure Login(const aID, aKey: WideString; out Data: OleVariant); safecall;
    // 获得单据流水帐号
    procedure GetNewBill(const BillKind: WideString; out Data: OleVariant);
      safecall;
    // 药品出库审核函数
    procedure CheckOut(const OutNo: WideString; out Data: OleVariant);
      safecall;
public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
end;

{ 缓冲池维护一个RDMs对列,向外界提供没有使用的RDMs }

TPoolManager = class(TObject)
private
    FRDMList: TList;
    FCurrentSemaphoreCount: Integer; //信号数
    FMaxSemaphoreCount: Integer;     //最大信号数
    FMaxDBSessionCount: Integer;     //最大连接数
    FActivePoolerCount: Integer;     //并发用户数
    FRDMTimeOut: Integer;            //运行超时
    FSemaphoreTimeOut: Integer;      //同步超时
    FCriticalSection: TCriticalSection;
    FSemaphore: THandle;
    FAppInfo: TAppInfo;
    FUserCount: Integer;

    function GetLock(Index: Integer): Boolean;
    function CreateNewInstance: IRDMSystem;
    function GetActivePoolerCount: Integer;
    function CloseALLRDM: Boolean;
    procedure ReleaseLock(Index: Integer; var Value: IRDMSystem);
    procedure ShowAppInfo;
public
    constructor Create;
    destructor Destroy; override;
    function LockRDM: IRDMSystem;
    procedure UnlockRDM(var Value: IRDMSystem);
    property CurrentSemaphoreCount: Integer read FCurrentSemaphoreCount;
    property MaxSemaphoreCount: Integer read FMaxSemaphoreCount;
    property MaxDBSessionCount: Integer read FMaxDBSessionCount;
    property ActivePoolerCount: Integer read GetActivePoolerCount;
    property RDMTimeOut: Integer read FRDMTimeOut;
    property SemaphoreTimeOut: Integer read FSemaphoreTimeOut;
    property UserCount: Integer read FUserCount;
end;

PRDM = ^TRDM;
TRDM = record
    Intf: IRDMSystem;
    InUse: Boolean; //表示是否真正使用该接口
    BeginUseTime: TDateTime; //开始Use该接口的时间,来判断此接口是否已经TimeOut
end;

var
PoolManager: TPoolManager;

implementation

uses uRDMSystem, uUtils;

{ TPoolManager类 }

constructor TPoolManager.Create;
begin
FRDMList := TList.Create;
FCriticalSection := TCriticalSection.Create;
FRDMTimeOut := 60;
FSemaphoreTimeOut := 5000;
FMaxDBSessionCount := 8;
FMaxSemaphoreCount := 5;
FCurrentSemaphoreCount := 5;
FSemaphore := CreateSemaphore(nil, FMaxSemaphoreCount, FMaxSemaphoreCount, nil);
end;

destructor TPoolManager.Destroy;
var
i: Integer;
begin
FCriticalSection.Free;
for i := 0 to FRDMList.Count - 1 do
begin
    PRDM(FRDMList[i]).Intf := nil;
    FreeMem(PRDM(FRDMList[i]));
end;
FRDMList.Free;
CloseHandle(FSemaphore);
inherited Destroy;
end;

function TPoolManager.GetLock(Index: Integer): Boolean;
begin
FCriticalSection.Enter;
try
    //检查是否运行超时,释放运行超时的接口
    if IsTimeOut(PRDM(FRDMList[Index]).BeginUseTime, RDMTimeOut) then
      PRDM(FRDMList[Index]).InUse := False;
    Result := not PRDM(FRDMList[Index]).InUse;
    //存在未使用的接口,记录下新的开始时间
    if Result then
    begin
      PRDM(FRDMList[Index]).InUse := True;
      PRDM(FRDMList[Index]).BeginUseTime := Now;
    end;
finally
    FCriticalSection.Leave;
end;
end;

procedure TPoolManager.ReleaseLock(Index: Integer; var Value: IRDMSystem);
begin
FCriticalSection.Enter;
try
    PRDM(FRDMList[Index]).InUse := False;
    Value := nil;
    ReleaseSemaphore(FSemaphore, 1, @FCurrentSemaphoreCount);
    Inc(FCurrentSemaphoreCount); //调用ReleaseSemaphore,当前同步信号数会加1
finally
    FCriticalSection.Leave;
end;
end;

function TPoolManager.CreateNewInstance: IRDMSystem;
var
p: PRDM;
begin
FCriticalSection.Enter;
try
    New(p);
    p.Intf := RDMFactory.CreateComObject(nil) as IRDMSystem;;
    p.InUse := True;
    p.BeginUseTime := Now;
    FRDMList.Add(p);
    Result := p.Intf;
finally
    FCriticalSection.Leave;
end;
end;

function TPoolManager.LockRDM: IRDMSystem;
var
i: Integer;
begin
ShowAppInfo;
Result := nil;
if WaitForSingleObject(FSemaphore, SemaphoreTimeOut) = WAIT_TIMEOUT then
    raise Exception.Create('应用服务器忙!');
for i := 0 to FRDMList.Count - 1 do
begin
    if GetLock(i) then
    begin
      Result := PRDM(FRDMList[i]).Intf;
      Exit;
    end;
end;
if FRDMList.Count < MaxDBSessionCount then
    Result := CreateNewInstance;
ShowAppInfo;
if Result = nil then { This shouldn't happen because of the sempahore locks }
    raise Exception.Create('不能锁定远程数据模块!');
end;

procedure TPoolManager.UnlockRDM(var Value: IRDMSystem);
var
i: Integer;
begin
for i := 0 to FRDMList.Count - 1 do
begin
    if Value = PRDM(FRDMList[i]).Intf then
    begin
      ReleaseLock(i, Value);
      break;
    end;
end;
ShowAppInfo;
end;

function TPoolManager.GetActivePoolerCount: Integer;
var
i: Integer;
begin
//初始化并发用户数据
Result := 0;
FActivePoolerCount := 0;
for i := 0 to FRDMList.Count - 1 do
begin
    if PRDM(FRDMList[i]).InUse then
      Inc(FActivePoolerCount);
    Result := FActivePoolerCount;
end;
end;

function TPoolManager.CloseALLRDM: Boolean;
var
i: Integer;
begin
for i := FRDMList.Count - 1 downto 0 do
begin
    FCriticalSection.Enter;
    try
      if not PRDM(FRDMList[i])^.InUse then
      try
        PRDM(FRDMList[i])^.Intf := nil;
        Dispose(PRDM(FRDMList[i]));
        FRDMList.Delete(i);
      except
      end;
    finally
      FCriticalSection.Leave;
    end;
end;
Result := True;
end;

{ 显示应用服务器资源使用情况 }
procedure TPoolManager.ShowAppInfo;
begin
with FAppInfo do
begin
    aUserCount := UserCount;
    aActivePoolerCount := ActivePoolerCount;
    aCurrentUsePoolerCount := FRDMList.Count;
    aMaxPoolerCount := MaxDBSessionCount;
    aPoolerTimeOut := RDMTimeOut;
    aSemaphoreTimeOut := SemaphoreTimeOut/1000;
    aCurrentSemaphoreCount := CurrentSemaphoreCount;
    aMaxSemaphoreCount := MaxSemaphoreCount;
end;
{$WARNINGS OFF}
PostMessage(Application.MainForm.Handle, WM_APPINFO, LongInt(@FAppInfo), 0);
{$WARNINGS ON}
end;


{ 包装服务器对象AppCenter类 }

constructor TAppCenter.Create(AOwner: TComponent);
begin
inherited;
//创建了一个TAppCenter对象,就表明有客户在请求COM服务
Inc(PoolManager.FUserCount);
//更新APP信息
PoolManager.ShowAppInfo;
end;

destructor TAppCenter.Destroy;
begin
Dec(PoolManager.FUserCount);
//当没有客户请求服务时,释放所有RDM对象
if PoolManager.FUserCount = 0 then PoolManager.CloseAllRDM;
PoolManager.ShowAppInfo;
inherited;
end;

function TAppCenter.LockRDM: IRDMSystem;
begin
Result := PoolManager.LockRDM;
end;

procedure TAppCenter.UnlockRDM(Value: IRDMSystem);
begin
PoolManager.UnlockRDM(Value);
end;

function TAppCenter.AS_ApplyUpdates(const ProviderName: WideString;
Delta: OleVariant; MaxErrors: Integer; out ErrorCount: Integer;
var OwnerData: OleVariant): OleVariant;
var
RDM: IRDMSystem;
begin
RDM := LockRDM;
try
    Result := RDM.AS_ApplyUpdates(ProviderName, Delta, MaxErrors, ErrorCount, OwnerData);
finally
    UnlockRDM(RDM);
end;
end;

function TAppCenter.AS_DataRequest(const ProviderName: WideString;
Data: OleVariant): OleVariant;
var
RDM: IRDMSystem;
begin
RDM := LockRDM;
try
    Result := RDM.AS_DataRequest(ProviderName, Data);
finally
    UnlockRDM(RDM);
end;
end;

procedure TAppCenter.AS_Execute(const ProviderName, CommandText: WideString;
var Params, OwnerData: OleVariant);
var
RDM: IRDMSystem;
begin
RDM := LockRDM;
try
    RDM.AS_Execute(ProviderName, CommandText, Params, OwnerData);
finally
    UnlockRDM(RDM);
end;
end;

function TAppCenter.AS_GetParams(const ProviderName: WideString;
var OwnerData: OleVariant): OleVariant;
var
RDM: IRDMSystem;
begin
RDM := LockRDM;
try
    Result := RDM.AS_GetParams(ProviderName, OwnerData);
finally
    UnlockRDM(RDM);
end;
end;

function TAppCenter.AS_GetProviderNames: OleVariant;
var
RDM: IRDMSystem;
begin
RDM := LockRDM;
try
    Result := RDM.AS_GetProviderNames;
finally
    UnlockRDM(RDM);
end;
end;

function TAppCenter.AS_GetRecords(const ProviderName: WideString;
Count: Integer; out RecsOut: Integer; Options: Integer;
const CommandText: WideString; var Params,
OwnerData: OleVariant): OleVariant;
var
RDM: IRDMSystem;
begin
RDM := LockRDM;
try
    Result := RDM.AS_GetRecords(ProviderName, Count, RecsOut, Options,
      CommandText, Params, OwnerData);
finally
    UnlockRDM(RDM);
end;
end;

function TAppCenter.AS_RowRequest(const ProviderName: WideString;
Row: OleVariant; RequestType: Integer;
var OwnerData: OleVariant): OleVariant;
var
RDM: IRDMSystem;
begin
RDM := LockRDM;
try
    Result := RDM.AS_RowRequest(ProviderName, Row, RequestType, OwnerData);
finally
    UnlockRDM(RDM);
end;
end;


procedure TAppCenter.Login(const aID, aKey: WideString;
out Data: OleVariant);
var
RDM: IRDMSystem;
begin
RDM := LockRDM;
try
    RDM.Login(aID, aKey, Data);
finally
    UnlockRDM(RDM);
end;
end;

procedure TAppCenter.GetNewBill(const BillKind: WideString;
out Data: OleVariant);
var
RDM: IRDMSystem;
begin
RDM := LockRDM;
try
    RDM.GetNewBill(BillKind, Data);
finally
    UnlockRDM(RDM);
end;
end;

procedure TAppCenter.CheckOut(const OutNo: WideString;
out Data: OleVariant);
var
RDM: IRDMSystem;
begin
RDM := LockRDM;
try
    RDM.CheckOut(OutNo, Data);
finally
    UnlockRDM(RDM);
end;
end;

initialization
PoolManager := TPoolManager.Create;
TComponentFactory.Create(ComServer, TAppCenter, Class_AppCenter,
    ciMultiInstance, tmApartment);

finalization
PoolManager.Free;

end.
posted on 2011-04-21 09:22  fyen  阅读(1772)  评论(2编辑  收藏  举报