You've already forked lazarus-ccr
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5438 8e941d3f-bd1b-0410-a28a-d453659cc2b4
560 lines
19 KiB
ObjectPascal
560 lines
19 KiB
ObjectPascal
{*********************************************************}
|
|
{* FlashFiler: Base component 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 ffllcomp;
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes,
|
|
SysUtils,
|
|
ffllbase,
|
|
fflllog,
|
|
ffsrmgr;
|
|
|
|
type
|
|
{ This type defines the possible states of a TffStateComponent. Values:
|
|
ffesInactive - The engine and its associated components (i.e., command
|
|
handlers and transports) are inactive.
|
|
ffesInitializing - The engine and its associated components are
|
|
initializing.
|
|
ffesStarting - The engine and its associates are starting.
|
|
ffesStarted - The engine and its associates are operational and
|
|
processing requests.
|
|
ffesShuttingDown - The engine and its associates are in the process of
|
|
shutting down.
|
|
ffesStopping - The engine is in the process of stopping but its
|
|
associated components are still active.
|
|
ffesStopped - The engine is inactive but its associates are still
|
|
active.
|
|
ffesUnsupported - Transport-specific. The transport is not supported
|
|
on this workstation. For example, an IPX/SPX transport is unsupported
|
|
if an IPX/SPX driver is not installed on the workstation.
|
|
ffesFailed - A failure occurred and the engine or transport may no
|
|
longer be used. A transport's state is set to ffesFailed if an error
|
|
occurs during startup.
|
|
}
|
|
TffState = (ffesInactive,
|
|
ffesInitializing,
|
|
ffesStarting,
|
|
ffesStarted,
|
|
ffesShuttingDown,
|
|
ffesStopping,
|
|
ffesStopped,
|
|
ffesUnsupported,
|
|
ffesFailed);
|
|
|
|
{ This class implements the basic functionality for associating a component
|
|
with a descendant of TffBaseLog. }
|
|
TffLoggableComponent = class(TffComponent)
|
|
protected
|
|
|
|
FEventLog : TffBaseLog;
|
|
{ The log to which events may be written. }
|
|
|
|
FLogEnabled : boolean;
|
|
{ If True then events may be written to the event log. }
|
|
|
|
function lcGetLogEnabled : boolean; virtual;
|
|
|
|
procedure lcLog(const aString : string); virtual;
|
|
{ Use this to write a string to the event log. }
|
|
|
|
{Begin !!.06}
|
|
procedure lcLogFmt(const aMsg : string; const args : array of const); virtual;
|
|
{ Use this method to write a formatted error string to the event log. }
|
|
{End !!.06}
|
|
|
|
procedure lcSetEventLog(anEventLog : TffBaseLog); virtual;
|
|
{ Sets the event log to be used by this component. }
|
|
|
|
procedure lcSetLogEnabled(const aEnabled : boolean); virtual;
|
|
|
|
public
|
|
|
|
constructor Create(aOwner : TComponent); override;
|
|
|
|
destructor Destroy; override;
|
|
|
|
procedure FFNotificationEx(const AOp : Byte; AFrom : TffComponent; {!!.11}
|
|
const AData : TffWord32); override; {!!.11}
|
|
{ When the freeing of the TffBaseLog is detected, this method
|
|
sets FEventLog to nil to avoid using the freed TffBaseLog. }
|
|
|
|
published
|
|
|
|
property EventLog : TffBaseLog read FEventLog write lcSetEventLog;
|
|
{ The event log to which the component may log messages. }
|
|
|
|
property EventLogEnabled : boolean
|
|
read lcGetLogEnabled
|
|
write lcSetLogEnabled
|
|
default False;
|
|
{ If True then events are logged to EventLog. }
|
|
|
|
end;
|
|
|
|
{ This class implements a basic state engine. }
|
|
TffStateComponent = class(TffLoggableComponent)
|
|
protected
|
|
|
|
scOnStateChange : TNotifyEvent;
|
|
{ Handler to be called when the component's state changes. }
|
|
|
|
scState : TffState;
|
|
{ The current state of the component. }
|
|
|
|
procedure scCheckInactive; virtual;
|
|
{ When setting certain properties or calling certain methods, this
|
|
method is called to ensure the object is inactive. If the
|
|
object is not inactive then this method raises exception
|
|
ffsce_MustBeInactive. }
|
|
|
|
procedure scCheckStarted; virtual;
|
|
{ When setting certain properties or calling certain methods, this
|
|
method is called to ensure the object is started. If the
|
|
object is not started then this method raises exception
|
|
ffsce_MustBeStarted. }
|
|
|
|
procedure scInitialize; virtual; abstract;
|
|
{ This method is called when the component is to perform
|
|
its initialization. }
|
|
|
|
procedure scPrepareForShutdown; virtual; abstract;
|
|
{ This method is called when the component is to prepare for
|
|
shutdown. }
|
|
|
|
procedure scShutdown; virtual; abstract;
|
|
{ This method is called when the component is to finalize its shutdown. }
|
|
|
|
procedure scStartup; virtual; abstract;
|
|
{ This method is called when the component is to complete the actions
|
|
required for it to do whatever work it is supposed to do. }
|
|
|
|
procedure scSetState(const aState : TffState); virtual;
|
|
{ Use this method to set the component's state. }
|
|
|
|
public
|
|
|
|
constructor Create(aOwner : TComponent); override;
|
|
|
|
destructor Destroy; override;
|
|
|
|
{$IFDEF DCC4OrLater} {!!.03}
|
|
procedure BeforeDestruction; override; {!!.03}
|
|
{$ENDIF} {!!.03}
|
|
|
|
procedure Shutdown; virtual;
|
|
{ Sets the component's State to ffesInactive. }
|
|
|
|
procedure Startup; virtual;
|
|
{ Sets the component's State to ffesStarted. }
|
|
|
|
procedure Stop; virtual;
|
|
{ Sets the component's State to ffesStopped. }
|
|
|
|
property State : TffState read scState write scSetState;
|
|
{ The current state of the component. }
|
|
|
|
published
|
|
|
|
property OnStateChange : TNotifyEvent
|
|
read scOnStateChange
|
|
write scOnStateChange;
|
|
{ Event handler called when the component's state changes. }
|
|
|
|
end;
|
|
|
|
{ This type of exception is raised by the various server components when
|
|
a component-related error occurs. For example, if the user or an application
|
|
tries to set the transport's servername property while the transport is
|
|
active. }
|
|
EffServerComponentError = class(Exception)
|
|
protected
|
|
sceErrorCode : longInt;
|
|
function sceGetErrorString : string;
|
|
public
|
|
constructor Create(const aMsg : string);
|
|
constructor CreateViaCode(const aErrorCode : Longint; aDummy : Boolean);
|
|
constructor CreateViaCodeFmt(const aErrorCode : Longint; args : array of const; aDummy : Boolean);
|
|
constructor CreateWithObj(aObj : TComponent; const aMsg : string);
|
|
|
|
property ErrorCode : longInt read sceErrorCode;
|
|
end;
|
|
|
|
|
|
{---Helper routines---}
|
|
function FFMapStateToString(const aState : TffState) : string;
|
|
{ Maps a state value to a string. }
|
|
procedure RaiseSCErrorCode(const aErrorCode : longInt);
|
|
procedure RaiseSCErrorCodeFmt(const aErrorCode : longInt;
|
|
args : array of const);
|
|
procedure RaiseSCErrorMsg(const aMsg : string);
|
|
procedure RaiseSCErrorObj(aObj : TComponent; const aMsg : string);
|
|
|
|
|
|
var
|
|
ffStrResServerCmp : TffStringResource;
|
|
{-The string resource providing access to the server component error
|
|
strings. }
|
|
|
|
const
|
|
{ The following array implements the server state engine as specified in
|
|
Section 3.4.3.14 of the FlashFiler 2.0 Design Document. Exceptions are
|
|
as follows:
|
|
|
|
1. If the current state is ffesInitializing & the target state is specified
|
|
as ffesInactive, the next state is ffesInactive.
|
|
|
|
2. If the current state is ffesStarting & the target state is specified
|
|
as ffesInactive, the next state is ffesInactive.
|
|
|
|
3. State ffesUnsupported not shown in diagram.
|
|
|
|
4. State ffesFailed not shown in diagram.
|
|
|
|
Exceptions 1 and 2 are allowed because we need a way to short-circuit
|
|
transports back to ffesInactive in the event they fail during initialization
|
|
or startup.
|
|
|
|
Given the current state of the engine and the target state of the engine,
|
|
this array identifies the state to which the engine should be moved.
|
|
|
|
The first dimension (vertical) of the array is the engine's current state.
|
|
The second dimension (horizontal) of the array is the engine's target state.
|
|
|
|
To get the next state, index into the array as follows:
|
|
|
|
nextState := ffEngineStateDiagram[<current state>, <target state>];
|
|
}
|
|
ffStateDiagram : array [TffState, TffState] of TffState =
|
|
{ Horizontal = destination state, Vertical = current state }
|
|
{ ffesInactive - ffesInitializing- ffesStarting - ffesStarted - ffesShuttingDown- ffesStopping - ffesStopped - ffesUnsupported- ffesFailed }
|
|
( ( ffesInactive, ffesInitializing, ffesInitializing, ffesInitializing, ffesInitializing, ffesInitializing, ffesInitializing, ffesUnsupported, ffesFailed), // ffesInactive
|
|
( ffesInactive, ffesStarting, ffesStarting, ffesStarting, ffesStarting, ffesStarting, ffesStarting, ffesInactive, ffesInactive), // ffesInitializing
|
|
( ffesInactive, ffesStarted, ffesStarting, ffesStarted, ffesStarted, ffesStarted, ffesStarted, ffesInactive, ffesInactive), // ffesStarting
|
|
( ffesShuttingDown, ffesStopping, ffesStopping, ffesStarted, ffesShuttingDown, ffesStopping, ffesStopping, ffesInactive, ffesInactive ), // ffesStarted
|
|
( ffesInactive, ffesInactive, ffesInactive, ffesInactive, ffesShuttingDown, ffesInactive, ffesInactive, ffesInactive, ffesInactive ), // ffesShuttingDown
|
|
( ffesStopped, ffesStopped, ffesStopped, ffesStopped, ffesStopped, ffesStopping, ffesStopped, ffesInactive, ffesInactive ), // ffesStopping
|
|
( ffesInitializing, ffesInitializing, ffesInitializing, ffesInitializing, ffesInitializing, ffesInitializing, ffesStopped, ffesInactive, ffesInactive), // ffesStopped
|
|
( ffesUnsupported, ffesUnsupported, ffesUnsupported, ffesUnsupported, ffesUnsupported, ffesUnsupported, ffesUnsupported, ffesUnsupported, ffesUnsupported), // ffesUnsupported
|
|
( ffesFailed, ffesFailed, ffesFailed, ffesFailed, ffesFailed, ffesFailed, ffesFailed, ffesFailed, ffesFailed) // ffesFailed
|
|
);
|
|
|
|
|
|
implementation
|
|
|
|
{$I ffllscst.inc}
|
|
{$R ffllscst.res}
|
|
|
|
resourcestring
|
|
ffcStateInactive = 'Inactive';
|
|
ffcStateInitializing = 'Initializing';
|
|
ffcStateStarting = 'Starting';
|
|
ffcStateStarted = 'Started';
|
|
ffcStateShuttingDown = 'Shutting down';
|
|
ffcStateStopping = 'Stopping';
|
|
ffcStateStopped = 'Stopped';
|
|
ffcStateUnsupported = 'Driver not installed';
|
|
ffcStateFailed = 'Failed';
|
|
|
|
{===TffLoggableComponent=============================================}
|
|
constructor TffLoggableComponent.Create(aOwner : TComponent);
|
|
begin
|
|
inherited Create(aOwner);
|
|
FEventLog := nil;
|
|
FLogEnabled := False;
|
|
end;
|
|
{--------}
|
|
destructor TffLoggableComponent.Destroy;
|
|
begin
|
|
if assigned(FEventLog) then
|
|
FEventLog.FFRemoveDependent(Self); {!!.11}
|
|
inherited Destroy;
|
|
end;
|
|
{--------}
|
|
function TffLoggableComponent.lcGetLogEnabled : boolean;
|
|
begin
|
|
Result := FLogEnabled;
|
|
end;
|
|
{--------}
|
|
procedure TffLoggableComponent.lcLog(const aString : string);
|
|
begin
|
|
if FLogEnabled and assigned(FEventLog) then
|
|
FEventLog.WriteString(aString);
|
|
end;
|
|
{Begin !!.06}
|
|
{--------}
|
|
procedure TffLoggableComponent.lcLogFmt(const aMsg : string; const args : array of const);
|
|
begin
|
|
if FLogEnabled and assigned(FEventLog) then
|
|
FEventLog.WriteStringFmt(aMsg, args);
|
|
end;
|
|
{End !!.06}
|
|
{--------}
|
|
procedure TffLoggableComponent.lcSetEventLog(anEventLog : TffBaseLog);
|
|
{Rewritten !!.11}
|
|
begin
|
|
if FEventLog <> anEventLog then begin
|
|
if assigned(FEventLog) then
|
|
FEventLog.FFRemoveDependent(Self);
|
|
|
|
FEventLog := anEventLog;
|
|
if assigned(FEventLog) then
|
|
FEventLog.FFAddDependent(Self);
|
|
end;
|
|
end;
|
|
{--------}
|
|
procedure TffLoggableComponent.lcSetLogEnabled(const aEnabled : boolean);
|
|
begin
|
|
FLogEnabled := aEnabled;
|
|
end;
|
|
{--------}
|
|
{Rewritten !!.11}
|
|
procedure TffLoggableComponent.FFNotificationEx(const AOp : Byte; AFrom : TffComponent;
|
|
const AData : TffWord32);
|
|
begin
|
|
inherited;
|
|
if (AFrom = FEventLog) and
|
|
(AOp in [ffn_Destroy, ffn_Remove]) then begin
|
|
FEventLog.FFRemoveDependent(Self);
|
|
FEventLog := nil;
|
|
end;
|
|
end;
|
|
{====================================================================}
|
|
|
|
{===TffStateComponent================================================}
|
|
constructor TffStateComponent.Create(aOwner : TComponent);
|
|
begin
|
|
inherited Create(aOwner);
|
|
scOnStateChange := nil;
|
|
scState := ffesInactive;
|
|
end;
|
|
{--------}
|
|
destructor TffStateComponent.Destroy;
|
|
begin
|
|
if scState <> ffesInactive then
|
|
scSetState(ffesInactive);
|
|
inherited Destroy;
|
|
end;
|
|
{Begin !!.03}
|
|
{$IFDEF DCC4OrLater}
|
|
{--------}
|
|
procedure TffStateComponent.BeforeDestruction;
|
|
begin
|
|
inherited;
|
|
|
|
FFNotifyDependents(ffn_Deactivate); {!!.04}
|
|
|
|
if scState <> ffesInactive then
|
|
scSetState(ffesInactive);
|
|
end;
|
|
{$ENDIF}
|
|
{End !!.03}
|
|
{--------}
|
|
procedure TffStateComponent.scCheckInactive;
|
|
begin
|
|
if not (scState in [ffesInactive, ffesUnsupported, ffesFailed]) then {!!.03}
|
|
RaiseSCErrorCode(ffsce_MustBeInactive);
|
|
end;
|
|
{--------}
|
|
procedure TffStateComponent.scCheckStarted;
|
|
begin
|
|
if scState <> ffesStarted then
|
|
RaiseSCErrorCode(ffsce_MustBeStarted);
|
|
end;
|
|
{--------}
|
|
procedure TffStateComponent.scSetState(const aState : TffState);
|
|
var
|
|
NextState : TffState;
|
|
OldState : TffState;
|
|
begin
|
|
|
|
if aState = scState then exit;
|
|
|
|
OldState := scState;
|
|
|
|
try
|
|
while scState <> aState do begin
|
|
NextState := ffStateDiagram[scState, aState];
|
|
{ If our next state is exactly our current state then there is no way
|
|
we can get to the destination state. This happens when the current
|
|
state is ffesUnsupported or ffesFailed. }
|
|
if NextState = scState then exit;
|
|
|
|
// if NextState = ffesShuttingDown then {!!.04}
|
|
// FFNotifyDependents(ffn_Deactivate); {!!.04}
|
|
|
|
scState := NextState;
|
|
case NextState of
|
|
ffesInactive :
|
|
scShutdown;
|
|
ffesInitializing :
|
|
scInitialize;
|
|
ffesStarting :
|
|
scStartup;
|
|
ffesShuttingDown :
|
|
scPrepareForShutdown;
|
|
end; { case }
|
|
if assigned(scOnStateChange) then
|
|
scOnStateChange(Self);
|
|
end; { while }
|
|
except
|
|
scState := OldState;
|
|
raise;
|
|
end;
|
|
end;
|
|
{--------}
|
|
procedure TffStateComponent.Shutdown;
|
|
begin
|
|
State := ffesInactive;
|
|
end;
|
|
{--------}
|
|
procedure TffStateComponent.Startup;
|
|
begin
|
|
State := ffesStarted;
|
|
end;
|
|
{--------}
|
|
procedure TffStateComponent.Stop;
|
|
begin
|
|
State := ffesStopped;
|
|
end;
|
|
{====================================================================}
|
|
|
|
{===Interfaced helper routines=======================================}
|
|
function FFMapStateToString(const aState : TffState) : string;
|
|
begin
|
|
case aState of
|
|
ffesInactive : Result := ffcStateInactive;
|
|
ffesInitializing : Result := ffcStateInitializing;
|
|
ffesStarting : Result := ffcStateStarting;
|
|
ffesStarted : Result := ffcStateStarted;
|
|
ffesShuttingDown : Result := ffcStateShuttingDown;
|
|
ffesStopping : Result := ffcStateStopping;
|
|
ffesStopped : Result := ffcStateStopped;
|
|
ffesUnsupported : Result := ffcStateUnsupported;
|
|
ffesFailed : Result := ffcStateFailed;
|
|
else
|
|
Result := '';
|
|
end; { case }
|
|
end;
|
|
{--------}
|
|
procedure RaiseSCErrorCode(const aErrorCode : longInt);
|
|
begin
|
|
raise EffServerComponentError.CreateViaCode(aErrorCode, False);
|
|
end;
|
|
{--------}
|
|
procedure RaiseSCErrorCodeFmt(const aErrorCode : longInt;
|
|
args : array of const);
|
|
begin
|
|
raise EffServerComponentError.CreateViaCode(aErrorCode, False);
|
|
end;
|
|
{--------}
|
|
procedure RaiseSCErrorMsg(const aMsg : string);
|
|
begin
|
|
raise EffServerComponentError.Create(aMsg);
|
|
end;
|
|
{--------}
|
|
procedure RaiseSCErrorObj(aObj : TComponent; const aMsg : string);
|
|
begin
|
|
raise EffServerComponentError.CreateWithObj(aObj, aMsg);
|
|
end;
|
|
{====================================================================}
|
|
|
|
{===EffServerComponentError==========================================}
|
|
constructor EffServerComponentError.Create(const aMsg : string);
|
|
begin
|
|
sceErrorCode := 0;
|
|
inherited CreateFmt(ffStrResServerCmp[ffsce_NoErrorCode], [aMsg]);
|
|
end;
|
|
{--------}
|
|
constructor EffServerComponentError.CreateViaCode(const aErrorCode : Longint; aDummy : Boolean);
|
|
var
|
|
Msg : string;
|
|
begin
|
|
sceErrorCode := aErrorCode;
|
|
Msg := sceGetErrorString;
|
|
inherited CreateFmt(ffStrResServerCmp[ffsce_HasErrorCode], [Msg, aErrorCode, aErrorCode]);
|
|
end;
|
|
{--------}
|
|
constructor EffServerComponentError.CreateViaCodeFmt(const aErrorCode : longInt;
|
|
args : array of const;
|
|
aDummy : Boolean);
|
|
var
|
|
Msg : string;
|
|
begin
|
|
sceErrorCode := aErrorCode;
|
|
Msg := sceGetErrorString;
|
|
inherited CreateFmt(ffStrResServerCmp[ffsce_HasErrorCode],
|
|
[format(Msg, args), aErrorCode, aErrorCode]);
|
|
end;
|
|
{--------}
|
|
constructor EffServerComponentError.CreateWithObj(aObj : TComponent;
|
|
const aMsg : string);
|
|
var
|
|
ObjName : string;
|
|
begin
|
|
sceErrorCode := 0;
|
|
if (aObj = nil) then
|
|
ObjName := ffStrResServerCmp[ffsce_NilPointer]
|
|
else begin
|
|
ObjName := aObj.Name;
|
|
if (ObjName = '') then
|
|
ObjName := Format(ffStrResServerCmp[ffsce_UnnamedInst], [aObj.ClassName]);
|
|
end;
|
|
inherited CreateFmt(ffStrResServerCmp[ffsce_InstNoCode], [ObjName, aMsg]);
|
|
end;
|
|
{--------}
|
|
function EffServerComponentError.sceGetErrorString : string;
|
|
begin
|
|
Result := ffStrResServerCmp[sceErrorCode];
|
|
end;
|
|
{====================================================================}
|
|
|
|
procedure FinalizeUnit;
|
|
begin
|
|
ffStrResServerCmp.Free;
|
|
end;
|
|
|
|
procedure InitializeUnit;
|
|
begin
|
|
ffStrResServerCmp := nil;
|
|
ffStrResServerCmp := TffStringResource.Create(hInstance, 'FF_SERVER_CMP_STRINGS');
|
|
end;
|
|
|
|
initialization
|
|
InitializeUnit;
|
|
|
|
finalization
|
|
FinalizeUnit;
|
|
|
|
end.
|