lazarus-ccr/components/flashfiler/sourcelaz/fflleng.pas
2016-12-07 13:31:59 +00:00

1224 lines
52 KiB
ObjectPascal

{*********************************************************}
{* FlashFiler: Base engine classes *}
{*********************************************************}
(* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is TurboPower FlashFiler
*
* The Initial Developer of the Original Code is
* TurboPower Software
*
* Portions created by the Initial Developer are Copyright (C) 1996-2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** *)
{$I ffdefine.inc}
unit fflleng;
interface
uses
Windows,
Classes,
ffhash,
ffllbase,
ffllcomp,
fflldict,
ffsrbde,
ffsrlock;
type
{ This type defines the actions for which an extender may be notified.
ffeaAfterCreateClient - Called after a client is created.
If an extender returns an error code other than
DBIERR_NONE, the client will not be added and the
error code returned to the client application. The
client application is responsible for catching the
resulting exception and interpreting the error code
as there may be no client-side resource string
associated with the error code.
- All "after" actions will ignore extender error messages
}
TffEngineAction = ({record actions}
ffeaBeforeRecRead, ffeaAfterRecRead,
ffeaBeforeRecInsert, ffeaAfterRecInsert, ffeaInsertRecFail,
ffeaBeforeRecUpdate, ffeaAfterRecUpdate, ffeaUpdateRecFail,
ffeaBeforeRecDelete, ffeaAfterRecDelete, ffeaDeleteRecFail,
{table actions}
ffeaBeforeTabRead,
ffeaBeforeTabUpdate, ffeaTabUpdateFail,
ffeaBeforeTabDelete, ffeaTabDeleteFail,
ffeaBeforeTabInsert, ffeaTabInsertFail,
ffeaBeforeTabRestruct, ffeaTabRestructFail,
ffeaBeforeTabPack, ffeaTabPackFail,
ffeaBeforeAddInx, ffeaTabAddInxFail,
ffeaBeforeRebuildInx, ffeaTabRebuildInxFail,
ffeaBeforeTableLock, ffeaAfterTableLock, ffeaTableLockFail,
{databaseactions}
ffeaBeforeDBRead,
ffeaBeforeDBUpdate, ffeaDBUpdateFail,
ffeaBeforeDBDelete, ffeaDBDeleteFail,
ffeaBeforeDBInsert, ffeaDBInsertFail,
ffeaBeforeChgAliasPath, ffeaChgAliasPathFail,
{transactions actions}
ffeaAfterStartTrans,
ffeaBeforeCommit, ffeaAfterCommit, ffeaCommitFail, {!!.06}
ffeaBeforeRollback, ffeaAfterRollback,
{cursor actions}
ffeaBeforeCursorClose,
{BLOB actions}
ffeaBeforeBLOBCreate, ffeaAfterBLOBCreate, ffeaBLOBCreateFail,
ffeaBeforeBLOBRead, ffeaAfterBLOBRead, ffeaBLOBReadFail,
ffeaBeforeBLOBWrite, ffeaAfterBLOBWrite, ffeaBLOBWriteFail,
ffeaBeforeBLOBDelete, ffeaAfterBLOBDelete, ffeaBLOBDeleteFail,
ffeaBeforeBLOBTruncate, ffeaAfterBLOBTruncate, ffeaBLOBTruncateFail,
ffeaBeforeBLOBGetLength, ffeaAfterBLOBGetLength, ffeaBLOBGetLengthFail,
ffeaBeforeBLOBFree, ffeaAfterBLOBFree, ffeaBLOBFreeFail,
ffeaBeforeFileBLOBAdd, ffeaAfterFileBLOBAdd, ffeaFileBLOBAddFail,
ffeaBeforeBLOBLinkAdd, ffeaAfterBLOBLinkAdd, ffeaBLOBLinkAddFail,
{client actions}
ffeaBeforeRemoveClient,
ffeaAfterCreateClient,
{misc actions}
ffeaNoAction {used when no fallback action needs to be taken}
);
TffInterestedActions = set of TffEngineAction;
{ Used by a monitor to register interest in a specific type of server object.
For example, TffSrBaseCursor and TffSrDatabase. }
TffServerObjectClass = class of TffObject;
TffBaseEngineMonitor = class; { forward }
TffBaseEngineExtender = class; { forward }
TffInterestStructure = class; { forward }
{ TffBaseServerEngine is an abstract, virtual class that specifies the
minimum interface for a local or remote server engine. The base engine
provides support for adding and removing monitors. }
TffBaseServerEngine = class(TffStateComponent)
protected {private}
FInterests : TffInterestStructure;
{-This data structure tracks the interest of various monitors. }
FMonitors : TffThreadList;
{-The monitors registered with the engine. After a monitor registers
itself with the engine, it identifies the types of server objects
in which it is interested. }
protected
{property access methods}
function bseGetAutoSaveCfg : Boolean; virtual; abstract;
function bseGetReadOnly : Boolean; virtual; abstract;
procedure bseSetAutoSaveCfg(aValue : Boolean); virtual; abstract;{!!.01}
procedure bseSetReadOnly(aValue : Boolean); virtual; abstract; {!!.01}
procedure scSetState(const aState : TffState); override;
procedure AddInterest(aMonitor : TffBaseEngineMonitor;
serverObjectClass : TffServerObjectClass); virtual;
{-A monitor uses this method to register interest in a specific type of
server object. }
{Begin !!.06}
function ProcessRequest(aClientID : TffClientID;
aMsgID : Longint;
aTimeout : Longint;
aRequestData : Pointer;
aRequestDataLen : Longint;
aRequestDataType : TffNetMsgDataType;
var aReply : Pointer;
var aReplyLen : Longint;
aReplyType : TffNetMsgDataType) : TffResult; virtual;
{ Backdoor method for sending a request to a server engine.
Should only be implemented by remote server engines. }
function ProcessRequestNoReply(aClientID : TffClientID;
aMsgID : Longint;
aTimeout : Longint;
aRequestData : Pointer;
aRequestDataLen : Longint ) : TffResult; virtual;
{ Backdoor method for sending a request, no reply expected, to a
server engine. Should only be implemented by remote server engines. }
{End !!.06}
procedure RemoveAllInterest(aMonitor : TffBaseEngineMonitor); virtual;
{-A monitor uses this method to unregister its interest for all classes
in which it previously expressed interest. }
procedure RemoveInterest(aMonitor : TffBaseEngineMonitor;
serverObjectClass : TffServerObjectClass); virtual;
{-A monitor uses this method to remove interest in a specific type of
server object. }
public
{creation/destruction}
constructor Create(aOwner : TComponent); override;
destructor Destroy; override;
procedure FFAddDependent(ADependent : TffComponent); override; {!!.11}
procedure FFRemoveDependent(ADependent : TffComponent); override; {!!.11}
function GetInterestedMonitors(const anObjectClass : TffServerObjectClass) : TffList;
{-Use this method to retrieve a list of engine monitors interested in a
particular server object class. If no monitors have registered
interest then nil is returned. Otherwise this function returns a
TffList containing one or more TffIntListItems. You can convert
a TffIntListItem into a TffBaseEngineMonitor as follows:
aMonitor := TffBaseEngineMonitor(TffIntListItem(TffList[index]).KeyAsInt);
NOTE: The recipient of this functions' result is responsible for
freeing the TffList.
}
procedure GetServerNames(aList : TStrings;
aTimeout : Longint); virtual; abstract;
{ Returns a list of the servers available through the server's
transport. }
{Begin !!.10}
{ Event logging }
procedure Log(const aMsg : string); virtual; abstract;
{-Use this method to log a string to the event log. }
procedure LogAll(const Msgs : array of string); virtual; abstract;
{-Use this method to log multiple strings to the event log. }
procedure LogFmt(const aMsg : string; args : array of const); virtual; abstract;
{-Use this method to log a formatted string to the event log. }
{End !!.10}
{transaction tracking}
function TransactionCommit(const aDatabaseID : TffDatabaseID) : TffResult; virtual; abstract;
function TransactionRollback(const aDatabaseID : TffDatabaseID) : TffResult; virtual; abstract;
function TransactionStart(const aDatabaseID : TffDatabaseID;
const aFailSafe : boolean) : TffResult; virtual; abstract;
{Begin !!.10}
function TransactionStartWith(const aDatabaseID : TffDatabaseID;
const aFailSafe : Boolean;
const aCursorIDs : TffPointerList) : TffResult; virtual; abstract;
{End !!.10}
{client related stuff}
function ClientAdd(var aClientID : TffClientID;
const aClientName : TffNetName;
const aUserID : TffName;
const timeout : Longint;
var aHash : TffWord32) : TffResult; virtual; abstract;
{Begin !!.11}
function ClientAddEx(var aClientID : TffClientID;
const aClientName : TffNetName;
const aUserID : TffName;
const timeout : Longint;
const aClientVersion : Longint;
var aHash : TffWord32) : TffResult; virtual; abstract;
{ Same as ClientAdd but client version is supplied via the aClientVersion
parameter. }
{End !!.11}
function ClientRemove(aClientID : TffClientID) : TffResult; virtual; abstract;
function ClientSetTimeout(const aClientID : TffClientID;
const aTimeout : Longint) : TffResult; virtual; abstract;
{client session related stuff}
function SessionAdd(const aClientID : TffClientID; const timeout : Longint;
var aSessionID : TffSessionID) : TffResult; virtual; abstract;
function SessionCloseInactiveTables(aClientID : TffClientID) : TffResult; virtual; abstract; {!!.06}
function SessionCount(aClientID : TffClientID; var aCount : integer) : TffResult; virtual; abstract;
function SessionGetCurrent(aClientID : TffClientID; var aSessionID : TffSessionID) : TffResult; virtual; abstract;
function SessionRemove(aClientID : TffClientID; aSessionID : TffSessionID) : TffResult; virtual; abstract;
function SessionSetCurrent(aClientID : TffClientID; aSessionID : TffSessionID) : TffResult; virtual; abstract;
function SessionSetTimeout(const aClientID : TffClientID;
const aSessionID : TffSessionID;
const aTimeout : Longint) : TffResult; virtual; abstract;
{database related stuff}
function DatabaseAddAlias(const aAlias : TffName;
const aPath : TffPath;
aCheckSpace : Boolean; {!!.11}
const aClientID : TffClientID)
: TffResult; virtual; abstract;
function DatabaseAliasList(aList : TList;
aClientID : TffClientID) : TffResult; virtual; abstract;
{-Return a list of database aliases. aList will contain zero or more
instances of PffAliasDescriptor. }
function RecoveryAliasList(aList : TList;
aClientID : TffClientID) : TffResult; virtual; abstract;
{-Return a list of database aliases for use by a journal recovery
engine. The functionality of this method is identical to
DatabaseAliasList except that it does not require the server engine
to be started. }
function DatabaseChgAliasPath(aAlias : TffName;
aNewPath : TffPath;
aCheckSpace : Boolean; {!!.11}
aClientID : TffClientID)
: TffResult; virtual; abstract;
function DatabaseClose(aDatabaseID : TffDatabaseID) : TffResult; virtual; abstract;
function DatabaseDeleteAlias(aAlias : TffName;
aClientID : TffClientID) : TffResult; virtual; abstract;
function DatabaseGetAliasPath(aAlias : TffName;
var aPath : TffPath;
aClientID : TffClientID) : TffResult; virtual; abstract;
function DatabaseGetFreeSpace(const aDatabaseID : TffDatabaseID;
var aFreeSpace : Longint) : TffResult; virtual; abstract;
function DatabaseModifyAlias(const ClientID : TffClientID;
const aAlias : TffName;
const aNewName : TffName;
const aNewPath : TffPath;
aCheckSpace : Boolean) {!!.11}
: TffResult; virtual; abstract;
function DatabaseOpen(aClientID : TffClientID;
const aAlias : TffName;
const aOpenMode : TffOpenMode;
const aShareMode : TffShareMode;
const aTimeout : Longint;
var aDatabaseID : TffDatabaseID) : TffResult; virtual; abstract;
function DatabaseOpenNoAlias(aClientID : TffClientID;
const aPath : TffPath;
const aOpenMode : TffOpenMode;
const aShareMode : TffShareMode;
const aTimeout : Longint;
var aDatabaseID : TffDatabaseID) : TffResult; virtual; abstract;
function DatabaseSetTimeout(const aDatabaseID : TffDatabaseID;
const aTimeout : Longint) : TffResult; virtual; abstract;
function DatabaseTableExists(aDatabaseID : TffDatabaseID;
const aTableName : TffTableName;
var aExists : Boolean) : TffResult; virtual; abstract;
function DatabaseTableList(aDatabaseID : TffDatabaseID;
const aMask : TffFileNameExt;
aList : TList) : TffResult; virtual; abstract;
function DatabaseTableLockedExclusive(aDatabaseID : TffDatabaseID;
const aTableName : TffTableName;
var aLocked : Boolean) : TffResult; virtual; abstract;
{-Return a list of the tables for the specified database that fit the
specified filename mask. aList will contain zero or more instances
of PffTableDescriptor. }
{rebuild status related stuff}
function RebuildGetStatus(aRebuildID : Longint;
const aClientID : TffClientID;
var aIsPresent : boolean;
var aStatus : TffRebuildStatus) : TffResult; virtual; abstract;
{table related stuff}
function TableAddIndex(const aDatabaseID : TffDatabaseID;
const aCursorID : TffCursorID;
const aTableName : TffTableName;
const aIndexDesc : TffIndexDescriptor) : TffResult; virtual; abstract;
function TableBuild(aDatabaseID : TffDatabaseID;
aOverWrite : boolean;
const aTableName : TffTableName;
aForServer : boolean;
aDictionary : TffDataDictionary) : TffResult; virtual; abstract;
function TableDelete(aDatabaseID : TffDatabaseID; const aTableName : TffTableName) : TffResult; virtual; abstract;
function TableDropIndex(aDatabaseID : TffDatabaseID;
aCursorID : TffCursorID;
const aTableName : TffTableName;
const aIndexName : TffDictItemName;
aIndexID : Longint) : TffResult; virtual; abstract;
function TableEmpty(aDatabaseID : TffDatabaseID;
aCursorID : TffCursorID;
const aTableName : TffTableName) : TffResult; virtual; abstract;
function TableGetAutoInc(aCursorID : TffCursorID;
var aValue : TffWord32) : TffResult; virtual; abstract;
function TableGetDictionary(aDatabaseID : TffDatabaseID;
const aTableName : TffTableName;
aForServer : boolean;
aStream : TStream) : TffResult; virtual; abstract;
function TableGetRecCount(aCursorID : TffCursorID;
var aRecCount : Longint) : TffResult; virtual; abstract;
function TableGetRecCountAsync(aCursorID : TffCursorID; {!!.10}
var aRebuildID : Longint) : TffResult; virtual; abstract; {!!.10}
function TableOpen(const aDatabaseID : TffDatabaseID;
const aTableName : TffTableName;
const aForServer : boolean;
const aIndexName : TffName;
aIndexID : Longint;
const aOpenMode : TffOpenMode;
aShareMode : TffShareMode;
const aTimeout : Longint;
var aCursorID : TffCursorID;
aStream : TStream) : TffResult; virtual; abstract;
function TablePack(aDatabaseID : TffDatabaseID;
const aTableName : TffTableName;
var aRebuildID : Longint): TffResult; virtual; abstract;
function TableRebuildIndex(aDatabaseID : TffDatabaseID;
const aTableName : TffTableName;
const aIndexName : TffName;
aIndexID : Longint;
var aRebuildID : Longint): TffResult; virtual; abstract;
function TableRename(aDatabaseID : TffDatabaseID; const aOldName, aNewName : TffName) : TffResult; virtual; abstract;
function TableRestructure(aDatabaseID : TffDatabaseID;
const aTableName : TffTableName;
aDictionary : TffDataDictionary;
aFieldMap : TffStringList;
var aRebuildID : Longint): TffResult; virtual; abstract;
function TableSetAutoInc(aCursorID : TffCursorID;
aValue : TffWord32) : TffResult; virtual; abstract;
{Begin !!.11}
function TableVersion(aDatabaseID : TffDatabaseID;
const aTableName : TffTableName;
var aVersion : Longint) : TffResult; virtual; abstract;
{End !!.11}
{table locks via cursor}
function TableIsLocked(aCursorID : TffCursorID; aLockType : TffLockType;
var aIsLocked : boolean) : TffResult; virtual; abstract;
function TableLockAcquire(aCursorID : TffCursorID; aLockType : TffLockType) : TffResult; virtual; abstract;
function TableLockRelease(aCursorID : TffCursorID; aAllLocks : boolean) : TffResult; virtual; abstract;
{cursor stuff}
function CursorClone(aCursorID : TffCursorID; aOpenMode : TffOpenMode;
var aNewCursorID : TffCursorID) : TffResult; virtual; abstract;
function CursorClose(aCursorID : TffCursorID) : TffResult; virtual; abstract;
function CursorCompareBookmarks(aCursorID : TffCursorID;
aBookmark1,
aBookmark2 : PffByteArray;
var aCompResult : Longint) : TffResult; virtual; abstract;
{Begin !!.02}
function CursorCopyRecords(aSrcCursorID,
aDestCursorID : TffCursorID;
aCopyBLOBs : Boolean) : TffResult; virtual; abstract;
{End !!.02}
function CursorDeleteRecords(aCursorID : TffCursorID) : TffResult; virtual; abstract; {!!.06}
function CursorGetBookmark(aCursorID : TffCursorID; aBookmark : PffByteArray) : TffResult; virtual; abstract;
function CursorGetBookmarkSize(aCursorID : TffCursorID;
var aSize : integer) : TffResult; virtual; abstract;
{Begin !!.03}
function CursorListBLOBFreeSpace(aCursorID : TffCursorID;
const aInMemory : Boolean;
aStream : TStream) : TffResult; virtual; abstract;
{End !!.03}
function CursorOverrideFilter(aCursorID : Longint;
aExpression : pCANExpr;
aTimeout : TffWord32) : TffResult; virtual; abstract;
function CursorResetRange(aCursorID : TffCursorID) : TffResult; virtual; abstract;
function CursorRestoreFilter(aCursorID : Longint) : TffResult; virtual; abstract;
function CursorSetRange(aCursorID : TffCursorID;
aDirectKey : boolean;
aFieldCount1 : integer;
aPartialLen1 : integer;
aKeyData1 : PffByteArray;
aKeyIncl1 : boolean;
aFieldCount2 : integer;
aPartialLen2 : integer;
aKeyData2 : PffByteArray;
aKeyIncl2 : boolean) : TffResult; virtual; abstract;
function CursorSetTimeout(const aCursorID : TffCursorID;
const aTimeout : Longint) : TffResult; virtual; abstract;
function CursorSetToBegin(aCursorID : TffCursorID) : TffResult; virtual; abstract;
function CursorSetToBookmark(aCursorID : TffCursorID; aBookmark : PffByteArray) : TffResult; virtual; abstract;
function CursorSetToCursor(aDestCursorID : TffCursorID; aSrcCursorID : TffCursorID) : TffResult; virtual; abstract;
function CursorSetToEnd(aCursorID : TffCursorID) : TffResult; virtual; abstract;
function CursorSetToKey(aCursorID : TffCursorID;
aSearchAction : TffSearchKeyAction;
aDirectKey : boolean;
aFieldCount : integer;
aPartialLen : integer;
aKeyData : PffByteArray) : TffResult; virtual; abstract;
function CursorSwitchToIndex(aCursorID : TffCursorID;
aIndexName : TffDictItemName;
aIndexID : integer;
aPosnOnRec : boolean) : TffResult; virtual; abstract;
function CursorSetFilter(aCursorID : TffCursorID;
aExpression : pCANExpr;
aTimeout : TffWord32) : TffResult; virtual; abstract;
{record stuff}
function RecordDelete(aCursorID : TffCursorID; aData : PffByteArray) : TffResult; virtual; abstract;
function RecordDeleteBatch(aCursorID : TffCursorID;
aBMCount : Longint;
aBMLen : Longint;
aData : PffByteArray;
aErrors : PffLongintArray) : TffResult; virtual; abstract;
function RecordExtractKey(aCursorID : TffCursorID; aData : PffByteArray; aKey : PffByteArray) : TffResult; virtual; abstract;
function RecordGet(aCursorID : TffCursorID; aLockType : TffLockType; aData : PffByteArray) : TffResult; virtual; abstract;
function RecordGetBatch(aCursorID : TffCursorID;
aRecCount : Longint;
aRecLen : Longint;
var aRecRead : Longint;
aData : PffByteArray;
var aError : TffResult) : TffResult; virtual; abstract;
function RecordGetForKey(aCursorID : TffCursorID;
aDirectKey : boolean;
aFieldCount : integer;
aPartialLen : integer;
aKeyData : PffByteArray;
aData : PffByteArray;
aFirstCall : Boolean) : TffResult; virtual; abstract;
function RecordGetNext(aCursorID : TffCursorID; aLockType : TffLockType; aData : PffByteArray) : TffResult; virtual; abstract;
function RecordGetPrior(aCursorID : TffCursorID; aLockType : TffLockType; aData : PffByteArray) : TffResult; virtual; abstract;
function RecordInsert(aCursorID : TffCursorID; aLockType : TffLockType; aData : PffByteArray) : TffResult; virtual; abstract;
function RecordInsertBatch(aCursorID : TffCursorID;
aRecCount : Longint;
aRecLen : Longint;
aData : PffByteArray;
aErrors : PffLongintArray) : TffResult; virtual; abstract;
function RecordIsLocked(aCursorID : TffCursorID; aLockType : TffLockType;
var aIsLocked : boolean) : TffResult; virtual; abstract;
function RecordModify(aCursorID : TffCursorID; aData : PffByteArray; aRelLock : boolean) : TffResult; virtual; abstract;
function RecordRelLock(aCursorID : TffCursorID; aAllLocks : boolean) : TffResult; virtual; abstract;
{BLOB stuff}
function BLOBCreate(aCursorID : TffCursorID;
var aBlobNr : TffInt64) : TffResult; virtual; abstract;
function BLOBDelete(aCursorID : TffCursorID; aBLOBNr : TffInt64) : TffResult; virtual; abstract;
{Begin !!.03}
function BLOBListSegments(aCursorID : TffCursorID;
aBLOBNr : TffInt64;
aStream : TStream) : TffResult; virtual; abstract;
{End !!.03}
function BLOBRead(aCursorID : TffCursorID;
aBLOBNr : TffInt64;
aOffset : TffWord32; {!!.06}
aLen : TffWord32; {!!.06}
var aBLOB;
var aBytesRead : TffWord32) {!!.06}
: TffResult; virtual; abstract;
function BLOBFree(aCursorID : TffCursorID; aBLOBNr : TffInt64;
readOnly : boolean) : TffResult; virtual; abstract;
function BLOBGetLength(aCursorID : TffCursorID; aBLOBNr : TffInt64;
var aLength : Longint) : TffResult; virtual; abstract;
function BLOBTruncate(aCursorID : TffCursorID; aBLOBNr : TffInt64;
aBLOBLength : Longint) : TffResult; virtual; abstract;
function BLOBWrite(aCursorID : TffCursorID; aBLOBNr : TffInt64;
aOffset : Longint;
aLen : Longint;
var aBLOB ) : TffResult; virtual; abstract;
function FileBLOBAdd(aCursorID : TffCursorID;
const aFileName : TffFullFileName;
var aBLOBNr : TffInt64) : TffResult; virtual; abstract;
{SQL Stuff }
function SQLAlloc(aClientID : TffClientID;
aDatabaseID : TffDatabaseID;
aTimeout : Longint;
var aStmtID : TffSqlStmtID) : TffResult; virtual; abstract;
function SQLExec(aStmtID : TffSqlStmtID;
aOpenMode : TffOpenMode;
var aCursorID : TffCursorID;
aStream : TStream) : TffResult; virtual; abstract;
function SQLExecDirect(aClientID : TffClientID;
aDatabaseID : TffDatabaseID;
aQueryText : PChar;
aTimeout : Longint;
aOpenMode : TffOpenMode;
var aCursorID : TffCursorID;
aStream : TStream) : TffResult; virtual; abstract;
function SQLFree(aStmtID : TffSqlStmtID) : TffResult; virtual; abstract;
function SQLPrepare(aStmtID : TffSqlStmtID;
aQueryText : PChar;
aStream : TStream) : TffResult; virtual; abstract;
function SQLSetParams(aStmtID : TffSqlStmtID;
aNumParams : word;
aParamDescs : Pointer;
aDataBuffer : PffByteArray;
aDataLen : integer;
aStream : TStream) : TffResult; virtual; abstract;
{misc stuff}
function GetServerDateTime(var aDateTime : TDateTime) : TffResult; virtual; abstract;
{Begin !!.10}
function GetServerSystemTime(var aSystemTime : TSystemTime)
: TffResult; virtual; abstract;
function GetServerGUID(var aGUID : TGUID)
: TffResult; virtual; abstract;
function GetServerID(var aUniqueID : TGUID)
: TffResult; virtual; abstract;
function GetServerStatistics(var aStats : TffServerStatistics)
: TffResult; virtual; abstract;
function GetCommandHandlerStatistics(const aCmdHandlerIdx : Integer;
var aStats : TffCommandHandlerStatistics)
: TffResult; virtual; abstract;
function GetTransportStatistics(const aCmdHandlerIdx : Integer;
const aTransportIdx : Integer;
var aStats : TffTransportStatistics)
: TffResult; virtual; abstract;
{End !!.10}
published
property IsReadOnly : Boolean
read bseGetReadOnly
write bseSetReadOnly {!!.01}
default False; {!!.01}
property NoAutoSaveCfg : Boolean
read bseGetAutoSaveCfg
write bseSetAutoSaveCfg {!!.01}
default False; {!!.01}
end;
{ This is the base implementation for an engine monitor. An engine monitor
attaches directly to a server engine and registers interest in specific
types of server objects. When an object of that type is opened in the
server, the monitor has the opportunity to express interest in the object.
The monitor can then supply an extender that will be associated with the
object and will receive notification of events pertaining to the object. }
TffBaseEngineMonitor = class(TffStateComponent)
protected
FServerEngine : TffBaseServerEngine;
procedure bemSetServerEngine(anEngine : TffBaseServerEngine); virtual;
{-Called when a monitor is associated with a server engine. If the
monitor is already associated with a server engine then it calls
OldEngine.RemoveMonitor. If the monitor is to be associated with
a new engine then it calls NewEngine.AddMonitor.
Subclasses should override this method to register interest in specific
types of server objects. }
{ State methods }
procedure scInitialize; override;
procedure scPrepareForShutdown; override;
procedure scShutdown; override;
procedure scStartup; override;
public
destructor Destroy; override;
procedure AddInterest(anObjectClass : TffServerObjectClass);
{-Use this method to have the monitor notify its parent server engine
of interest in a server object class. }
procedure FFNotificationEx(const AOp : Byte; AFrom : TffComponent; {!!.11}
const AData : TffWord32); override; {!!.11}
procedure RemoveAllInterest;
{-Use this method to have the monitor tells its parent engine to remove
all interests of the monitor. }
procedure RemoveInterest(anObjectClass : TffServerObjectClass);
{-Use this method to have the monitor tells its parent engine to remove
its interest in the specified object class. }
function Interested(aServerObject : TffObject) : TffBaseEngineExtender; virtual; abstract;
{ This function is called from the server when an object (e.g., cursor)
is first opened. If the monitor is interested in receiving events
for the object, it must create and return an instance of a class that
can handle events for the object. Otherwise it should return nil.
This method is called only for the type of objects in which the monitor
previously expressed interested.
When deriving a class from TffBaseEngineMonitor, it is up to the
extender designer to verify the class of ServerObject is one that is
expected.
}
published
property ServerEngine : TffBaseServerEngine read FServerEngine
write bemSetServerEngine;
{ Associates an engine monitor with an engine. }
end;
{ This is the base class for engine extenders. An engine extender is attached
to a specific type of server object as governed by an engine monitor. The
types of notifications received by the extender depend upon the type of
object being extended.
An extender is freed when the server object with which it is associated
is freed. }
TffBaseEngineExtender = class(TffObject)
protected
FParent : TffBaseEngineMonitor;
FActions : TffInterestedActions;
{ Set of actions extender is interested in.}
public
constructor Create(aOwner : TffBaseEngineMonitor); virtual;
function Notify(aServerObject : TffObject;
aAction : TffEngineAction) : TffResult; virtual; abstract;
{ This method is called when the extender is to be notified of an
action affecting the server object with which the extender is
associated. If the extender performs its operations, whatever they
may be, then this function should return DBIERR_NONE. If a failure
occurs and the server should discontinue the current operation with this
server object, this function should return an error code other than
DBIERR_NONE.
Some actions may pay attention to the error codes while other actions
may ignore the error codes. If an action pays attention to the error
code then extenders "after" the extender returning the error will not
be notified of the action.
}
property InterestedActions : TffInterestedActions
read FActions;
{ The set of actions in which the extender is interested. }
end;
{ The following class is used to track a monitor's interest. It stores
data in the following manner:
1. To support retrieval of all monitors interested in a particular
class of object, it creates a hash table where the hash is based
on the class' name. The hash bucket points to a list of monitors.
2. To support removal of all interest for a monitor, it maintains a
separate hash table where the hash is based upon the monitor}
TffInterestStructure = class(TffObject)
private
FHashByInterest : TffHash;
{ Given a server object class, this hash table returns a list of the
monitors interested in that object class. }
FHashByMonitor : TffHash;
{ Given an engine monitor, this hash table returns a list of the
object classes in which the monitor has expressed interest. We use
this data structure in RemoveAllInterest to speed up our search
for the monitors in FHashByInterest. }
FPortal : TffReadWritePortal;
protected
procedure DisposeList(Sender : TffBaseHashTable; aData : pointer);
{-This method is called when a hash table entry is removed. }
procedure RemoveInterestPrim(const aMonitor : TffBaseEngineMonitor;
const anObjectClass : TffServerObjectClass);
{-This method removes an interest entry from the FHashByInterest
hash table. }
public
constructor Create;
destructor Destroy; override;
procedure AddInterest(const aMonitor : TffBaseEngineMonitor;
const anObjectClass : TffServerObjectClass);
{-Use this method to add a monitor's interest in a certain class. }
function BeginRead : TffInterestStructure;
{-Use this method to obtain read access to the data. }
function BeginWrite : TffInterestStructure;
{-Use this method to obtain write access to the data. }
procedure EndRead;
{-This method must be called after BeginRead once read access is no
longer needed. }
procedure EndWrite;
{-This method must be called after BeginWrite once write access is no
longer needed. }
function GetInterestedMonitors(const anObjectClass : TffServerObjectClass) : TffList;
{-Use this method to retrieve a list of engine monitors interested in a
particular server object class. If no monitors have registered
interest then nil is returned. Otherwise this function returns a
TffList containing one or more TffIntListItems. You can convert
a TffIntListItem into a TffBaseEngineMonitor as follows:
aMonitor := TffBaseEngineMonitor(TffIntListItem(TffList[index]).KeyAsInt);
NOTE: The recipient of this functions' result is responsible for
freeing the TffList.
}
procedure RemoveAllInterest(const aMonitor : TffBaseEngineMonitor);
{-Use this method to remove interest in all things for which a monitor
previously registered interest. }
procedure RemoveInterest(const aMonitor : TffBaseEngineMonitor;
const anObjectClass : TffServerObjectClass);
{-Use this method to remove a monitor's interest in a certain class. }
end;
var
FFServerEngines : TffThreadList;
implementation
{===TffBaseServerEngine==============================================}
constructor TffBaseServerEngine.Create(aOwner : TComponent);
var
aListItem : TffIntListItem;
begin
inherited Create(aOwner);
{ Add our instance to the global server list }
aListItem := TffIntListItem.Create(Longint(Self));
with FFServerEngines.BeginWrite do
try
Insert(aListItem);
finally
EndWrite;
end;
FInterests := TffInterestStructure.Create;
FMonitors := TffThreadList.Create;
end;
{--------}
destructor TffBaseServerEngine.Destroy;
begin
FFNotifyDependents(ffn_Destroy); {!!.11}
FMonitors.Free; {!!.11}
if assigned(FInterests) then begin
FInterests.Free;
FInterests := nil;
end;
{ Remove our instance from the global server list }
with FFServerEngines.BeginWrite do
try
Delete(Longint(Self));
finally
EndWrite;
end;
inherited Destroy;
end;
{--------}
procedure TffBaseServerEngine.scSetState(const aState : TffState);
var
Idx : Longint;
NextState : TffState;
OldState : TffState;
Monitor : TFFBaseEngineMonitor;
begin
if aState = scState then exit;
OldState := scState;
try
if Assigned(FMonitors) then
with FMonitors.BeginRead do
try
while scState <> aState do begin
{ Based upon our current state & the target state, get the next state. }
NextState := ffStateDiagram[scState, aState];
{ Move all monitors to the specified state. }
for Idx := Pred(Count) downto 0 do begin
Monitor := TffBaseEngineMonitor(TffIntListItem(Items[Idx]).KeyAsInt);
Monitor.State := NextState;
end;
{ Change our state. }
scState := NextState;
{ Call the appropriate internal method for this state. }
case NextState of
ffesInactive, ffesStopped :
scShutdown;
ffesInitializing :
scInitialize;
ffesStarting :
scStartup;
ffesShuttingDown, ffesStopping :
scPrepareForShutdown;
end; { case }
if assigned(scOnStateChange) then
scOnStateChange(Self);
end; { while }
finally
EndRead;
end
else
inherited;
except
scState := OldState;
raise;
end;
end;
{--------}
procedure TffBaseServerEngine.AddInterest(aMonitor : TffBaseEngineMonitor;
serverObjectClass : TffServerObjectClass);
begin
with FInterests.BeginWrite do
try
AddInterest(aMonitor, serverObjectClass);
finally
EndWrite;
end;
end;
{Begin !!.11}
{--------}
procedure TffBaseServerEngine.FFAddDependent(ADependent : TffComponent);
var
aListItem : TffIntListItem;
begin
inherited;
if ADependent is TffBaseEngineMonitor then begin
aListItem := TffIntListItem.Create(Longint(ADependent));
with FMonitors.BeginWrite do
try
FMonitors.Insert(aListItem);
finally
EndWrite;
end;
end;
end;
{--------}
procedure TffBaseServerEngine.FFRemoveDependent(ADependent : TffComponent);
begin
inherited;
if ADependent is TffBaseEngineMonitor then
with FMonitors.BeginWrite do
try
Delete(Longint(ADependent));
RemoveAllInterest(TffBaseEngineMonitor(ADependent));
finally
EndWrite;
end;
end;
{End !!.11}
{--------}
function TffBaseServerEngine.GetInterestedMonitors
(const anObjectClass : TffServerObjectClass) : TffList;
begin
with FInterests.BeginRead do
try
Result := FInterests.GetInterestedMonitors(anObjectClass);
finally
EndRead;
end;
end;
{Begin !!.06}
{--------}
function TffBaseServerEngine.ProcessRequest(aClientID : TffClientID;
aMsgID : Longint;
aTimeout : Longint;
aRequestData : Pointer;
aRequestDataLen : Longint;
aRequestDataType : TffNetMsgDataType;
var aReply : Pointer;
var aReplyLen : Longint;
aReplyType : TffNetMsgDataType) : TffResult;
begin
{ Do nothing. }
Result := DBIERR_NONE;
end;
{--------}
function TffBaseServerEngine.ProcessRequestNoReply(aClientID : TffClientID;
aMsgID : Longint;
aTimeout : Longint;
aRequestData : Pointer;
aRequestDataLen : Longint ) : TffResult;
begin
{ Do nothing. }
Result := DBIERR_NONE;
end;
{End !!.06}
{--------}
procedure TffBaseServerEngine.RemoveAllInterest(aMonitor : TffBaseEngineMonitor);
begin
with FInterests.BeginWrite do
try
RemoveAllInterest(aMonitor);
finally
EndWrite;
end;
end;
{--------}
procedure TffBaseServerEngine.RemoveInterest(aMonitor : TffBaseEngineMonitor;
serverObjectClass : TffServerObjectClass);
begin
with FInterests.BeginWrite do
try
RemoveInterest(aMonitor, serverObjectClass);
finally
EndWrite;
end;
end;
{====================================================================}
{===TffBaseEngineMonitor=============================================}
destructor TffBaseEngineMonitor.Destroy;
begin
if assigned(FServerEngine) then
FServerEngine.FFRemoveDependent(Self); {!!.11}
inherited Destroy;
end;
{--------}
procedure TffBaseEngineMonitor.AddInterest(anObjectClass : TffServerObjectClass);
begin
if assigned(FServerEngine) then
FServerEngine.AddInterest(Self, anObjectClass);
end;
{--------}
procedure TffBaseEngineMonitor.bemSetServerEngine(anEngine : TffBaseServerEngine);
{Rewritten !!.11}
begin
if anEngine <> FServerEngine then begin
if assigned(FServerEngine) then
FServerEngine.FFRemoveDependent(Self);
if assigned(anEngine) then
anEngine.FFAddDependent(Self);
FServerEngine := anEngine;
end;
end;
{Begin !!.11}
{--------}
procedure TffBaseEngineMonitor.FFNotificationEx(const AOp : Byte; AFrom : TffComponent;
const AData : TffWord32);
begin
inherited;
if (AFrom = FServerEngine) and
(AOp in [ffn_Destroy, ffn_Remove]) then begin
FServerEngine.FFRemoveDependent(Self);
FServerEngine := nil;
end;
end;
{End !!.11}
{--------}
procedure TffBaseEngineMonitor.RemoveAllInterest;
begin
if assigned(FServerEngine) then
FServerEngine.RemoveAllInterest(Self);
end;
{--------}
procedure TffBaseEngineMonitor.RemoveInterest(anObjectClass : TffServerObjectClass);
begin
if assigned(FServerEngine) then
FServerEngine.RemoveInterest(Self, anObjectClass);
end;
{--------}
procedure TffBaseEngineMonitor.scInitialize;
begin
{ Do nothing - avoid abstract error }
end;
{--------}
procedure TffBaseEngineMonitor.scPrepareForShutdown;
begin
{ Do nothing - avoid abstract error }
end;
{--------}
procedure TffBaseEngineMonitor.scShutdown;
begin
{ Do nothing - avoid abstract error }
end;
{--------}
procedure TffBaseEngineMonitor.scStartup;
begin
{ Do nothing - avoid abstract error }
end;
{====================================================================}
{===TffInterestStructure=============================================}
constructor TffInterestStructure.Create;
begin
inherited Create;
FHashByInterest := TffHash.Create(0);
FHashByInterest.OnDisposeData := DisposeList;
FHashByMonitor := TffHash.Create(0);
FHashByMonitor.OnDisposeData := DisposeList;
FPortal := TffReadWritePortal.Create;
end;
{--------}
destructor TffInterestStructure.Destroy;
begin
if assigned(FHashByInterest) then
FHashByInterest.Free;
if assigned(FHashByMonitor) then
FHashByMonitor.Free;
if assigned(FPortal) then
FPortal.Free;
inherited Destroy;
end;
{--------}
procedure TffInterestStructure.AddInterest(const aMonitor : TffBaseEngineMonitor;
const anObjectClass : TffServerObjectClass);
var
MonitorList : TffList;
Item : TffIntListItem;
begin
{ Has interest already been registered in the class? }
Item := TffIntListItem.Create(Longint(aMonitor));
MonitorList := FHashByInterest.Get(Longint(anObjectClass));
if assigned(MonitorList) then begin
{ If so then append the new interest. }
MonitorList.Insert(Item);
end else begin
{ Otherwise, create a new entry and add the interest. }
MonitorList := TffList.Create;
MonitorList.Insert(Item);
FHashByInterest.Add(Longint(anObjectClass), pointer(MonitorList));
end;
{ Has this monitor registered for any other classes? }
Item := TffIntListItem.Create(Longint(anObjectClass));
MonitorList := FHashByMonitor.Get(Longint(aMonitor));
if assigned(MonitorList) then begin
{ If so then add this entry to the hash for monitors. }
MonitorList.Insert(Item);
end else begin
{ Otherwise, create a new entry for the monitor. }
MonitorList := TffList.Create;
MonitorList.Insert(Item);
FHashByMonitor.Add(Longint(aMonitor), pointer(MonitorList));
end;
end;
{--------}
function TffInterestStructure.BeginRead : TffInterestStructure;
begin
FPortal.BeginRead;
Result := Self;
end;
{--------}
function TffInterestStructure.BeginWrite : TffInterestStructure;
begin
FPortal.BeginWrite;
Result := Self;
end;
{--------}
procedure TffInterestStructure.DisposeList(Sender : TffBaseHashTable; aData : pointer);
var
Index : Longint;
ItemList : TffList;
begin
if assigned(aData) then begin
ItemList := TffList(aData);
{ Free the items in the list. }
for Index := pred(ItemList.Count) downto 0 do
ItemList[Index].Free;
ItemList.Free;
end;
end;
{--------}
procedure TffInterestStructure.EndRead;
begin
FPortal.EndRead;
end;
{--------}
procedure TffInterestStructure.EndWrite;
begin
FPortal.EndWrite;
end;
{--------}
function TffInterestStructure.GetInterestedMonitors
(const anObjectClass : TffServerObjectClass) : TffList;
var
anItem : TffIntListItem;
Index : Longint;
MonitorList : TffList;
begin
Result := nil;
{ Get the list of monitors interested in this object class. }
MonitorList := FHashByInterest.Get(Longint(anObjectClass));
{ If there are monitors, copy the info over to the result list. }
if assigned(MonitorList) then begin
Result := TffList.Create;
for Index := 0 to pred(MonitorList.Count) do begin
anItem := TffIntListItem.Create(TffIntListItem(MonitorList[Index]).KeyAsInt);
Result.Insert(anItem);
end;
end;
end;
{--------}
procedure TffInterestStructure.RemoveAllInterest(const aMonitor : TffBaseEngineMonitor);
var
Index : integer;
ClassList : TffList;
begin
{ Do we have any interests registered for this monitor? }
ClassList := FHashByMonitor.Get(Longint(aMonitor));
if assigned(ClassList) then begin
{ For each class in which the monitor registered interest, remove the
monitor from that class' list in FHashByInterest. }
for Index := pred(ClassList.Count) downto 0 do
RemoveInterestPrim(aMonitor,
TffServerObjectClass(TffIntListItem(ClassList[Index]).KeyAsInt));
{ Now get rid of the entry for this monitor. }
FHashByMonitor.Remove(Longint(aMonitor));
end;
end;
{--------}
procedure TffInterestStructure.RemoveInterest(const aMonitor : TffBaseEngineMonitor;
const anObjectClass : TffServerObjectClass);
var
ItemList : TffList;
begin
{ Remove the monitor's interest for this specific class. }
RemoveInterestPrim(aMonitor, anObjectClass);
{ Now remove the class from the monitor's list of interests. }
ItemList := FHashByMonitor.Get(Longint(aMonitor));
if assigned(ItemList) then
ItemList.Delete(Longint(anObjectClass));
{ If our list is empty then get rid of it. }
if ItemList.Count = 0 then
FHashByInterest.Remove(Longint(aMonitor));
end;
{--------}
procedure TffInterestStructure.RemoveInterestPrim(const aMonitor : TffBaseEngineMonitor;
const anObjectClass : TffServerObjectClass);
var
MonitorList : TffList;
begin
MonitorList := FHashByInterest.Get(Longint(anObjectClass));
{ If we did find a set of interests for the specified object class,
scan through it and eliminate registrations for the specified monitor. }
if assigned(MonitorList) then
MonitorList.Delete(aMonitor);
{ If our list is empty then get rid of it. }
if MonitorList.Count = 0 then
FHashByInterest.Remove(Longint(anObjectClass));
end;
{====================================================================}
constructor TffBaseEngineExtender.Create(aOwner : TffBaseEngineMonitor);
begin
inherited Create; {!!.02}
FParent := aOwner;
FActions := [];
end;
{====================================================================}
procedure FinalizeUnit;
begin
FFServerEngines.Free;
end;
procedure InitializeUnit;
begin
FFServerEngines := TffThreadList.Create;
end;
initialization
InitializeUnit;
finalization
FinalizeUnit;
end.