Componentes.Terceros.RemObj.../internal/5.0.23.613/1/RemObjects SDK for Delphi/Source/uROEventRepository.pas
david 2824855ea7 - Modificación del paquete RemObjects_Core_D10 para que sea un paquete de runtime/designtime (antes era designtime sólo)
- Recompilación en Delphi10 de todos los paquetes de RO para generar las DCU's en Lib\D10
- Recompilación en Delphi10 de todos los paquetes de DA para generar las DCU's en Lib\D10

git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.RemObjects@9 b6239004-a887-0f4b-9937-50029ccdca16
2007-09-10 14:06:19 +00:00

1623 lines
48 KiB
ObjectPascal

unit uROEventRepository;
{----------------------------------------------------------------------------}
{ RemObjects SDK Library - Core Library }
{ }
{ compiler: Delphi 5 and up, Kylix 2 and up }
{ platform: Win32, Linux }
{ }
{ (c)opyright RemObjects Software. all rights reserved. }
{ }
{ Using this code requires a valid license of the RemObjects SDK }
{ which can be obtained at http://www.remobjects.com. }
{----------------------------------------------------------------------------}
{$I RemObjects.inc}
interface
uses
Classes, SysUtils, SyncObjs, Contnrs,
uROSessions, uROClientIntf, uROClient, uROTypes, uROClasses, uROServerIntf;
type
IROEventsInvoker = interface;
TROEventReceiver = class;
TROSessionReference = class;
TROEventRepository = class;
TROInvokerInvokeMethod = procedure(__EventReceiver : TROEventReceiver; const aMessage : IROMEssage; const aTarget : IInterface) of object;
{ IROEventRepository }
IROEventRepository = interface
['{35D49EF1-F62C-4985-B092-8B09D235D81B}']
procedure AddSession(aSessionID : TGUID);
procedure RemoveSession(aSessionID : TGUID);
procedure StoreEventData(SourceSessionID : TGUID; Data : Binary;
const ExcludeSender: Boolean;
const ExcludeSessionList: Boolean;
const SessionList: String);
function GetEventData(SessionID : TGUID; var TargetStream : Binary) : integer;
end;
{ IROEventsInvoker }
IROEventsInvoker = interface
['{A7FF5762-8208-4A91-B6C2-5D4ECB014EE9}']
procedure Execute(const aTarget : TObject; EventData: TStream);
end;
TROSessionEvent = procedure(Sender : TROEventRepository ; const SessionID : TGUID) of object;
{ TROEventRepository }
TROEventRepository = class(TROComponent, IROEventRepository)
private
fSessionManager: TROCustomSessionManager;
fMessage: TROMessage;
fOnBeforeAddSession: TROSessionEvent;
fOnAfterRemoveSession: TROSessionEvent;
fOnAfterAddSession: TROSessionEvent;
fOnBeforeRemoveSession: TROSessionEvent;
procedure SetMessage(const Value: TROMessage);
protected
procedure SetSessionManager(const Value: TROCustomSessionManager); virtual;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
{ Virtuals }
procedure DoStoreEventData(SourceSessionID : TGUID; Data : Binary;
const ExcludeSender: Boolean;
const ExcludeSessionList: Boolean;
const SessionList: String); virtual; abstract;
function DoGetEventData(SessionID : TGUID; var TargetStream : Binary) : integer; virtual; abstract;
procedure DoAddSession(aSessionID : TGUID); overload; virtual; abstract;
procedure DoAddSession(aSessionID : TGUID; aActiveEventServer: IROActiveEventServer); overload; virtual;
procedure DoRemoveSession(aSessionID : TGUID); virtual; abstract;
function QueryInterface(const IID: TGUID; out Obj): HResult; override;
public
{ IROEventRepository }
procedure StoreEventData(SourceSessionID : TGUID; Data : Binary;
const ExcludeSender: Boolean;
const ExcludeSessionList: Boolean;
const SessionList: String);
function GetEventData(SessionID : TGUID; var TargetStream : Binary) : integer;
procedure AddSession(aSessionID : TGUID); overload;
procedure AddSession(aSessionID: TGUID; aActiveEventServer: IROActiveEventServer); overload;
procedure RemoveSession(aSessionID : TGUID);
procedure CheckProperties; virtual;
// procedure DeleteEventData(anEvent: TROEventData); virtual;
published
property Message : TROMessage read fMessage write SetMessage;
property SessionManager : TROCustomSessionManager read fSessionManager write SetSessionManager;
property OnBeforeAddSession : TROSessionEvent read fOnBeforeAddSession write fOnBeforeAddSession;
property OnAfterAddSession : TROSessionEvent read fOnAfterAddSession write fOnAfterAddSession;
property OnAfterRemoveSession : TROSessionEvent read fOnAfterRemoveSession write fOnAfterRemoveSession;
property OnBeforeRemoveSession : TROSessionEvent read fOnBeforeRemoveSession write fOnBeforeRemoveSession;
end;
TROSessionRefToEventDataLink = class;
IROActiveEventServerList = interface
['{C6ACE445-267E-4217-9A9C-1D357A7CB3BF}']
function GetNext: IROActiveEventServerList;
procedure SetNext(aData: IROActiveEventServerList);
function GetServer: IROActiveEventServer;
property Server: IROActiveEventServer read GetServer;
property Next: IROActiveEventServerList read GetNext write SetNext;
procedure DispatchEvent(anEventDataItem : TROEventData; aSessionReference : TGUID; aSender: TObject);
end;
TIROActiveEventServerList = class(TInterfacedObject, IROActiveEventServerList)
private
fNext: IROActiveEventServerList;
fServer: IROActiveEventServer;
public
constructor Create(aNext: IROActiveEventServerList; aItem: IROActiveEventServer);
class function AddListener(aList: IROActiveEventServerList; aItem: IROActiveEventServer): IROActiveEventServerList;
class function RemoveListener(aList: IROActiveEventServerList; aItem: IROActiveEventServer): IROActiveEventServerList;
function GetNext: IROActiveEventServerList;
function GetServer: IROActiveEventServer;
procedure SetNext(aData: IROActiveEventServerList);
procedure DispatchEvent(anEventDataItem : TROEventData; aSessionReference : TGUID; aSender: TObject);
end;
{ TROSessionReference }
TROSessionReference = class
private
fTail: TROSessionRefToEventDataLink;
fHead: TROSessionRefToEventDataLink;
fSessionID: TGUID;
ActiveEventReference: IROActiveEventServerList;
function GetHead: TROSessionRefToEventDataLink;
function GetTail: TROSessionRefToEventDataLink;
public
constructor Create(aSessionID : TGUID);
property SessionID : TGUID read fSessionID;
property Head : TROSessionRefToEventDataLink read GetHead write fHead;
property Tail : TROSessionRefToEventDataLink read GetTail write fTail;
end;
{ TROSessionRefToEventDataLink }
TROSessionRefToEventDataLink = class
private
fNext: TROSessionRefToEventDataLink;
fEventData: TROEventData;
fSessionReference: TROSessionReference;
public
constructor Create(anEventDataItem : TROEventData; aSessionReference : TROSessionReference);
destructor Destroy; override;
property EventData : TROEventData read fEventData;
property SessionReference : TROSessionReference read fSessionReference;
property Next: TROSessionRefToEventDataLink read fNext write fNext;
end;
{ TROInMemoryEventRepository }
TROInMemoryEventRepository = class(TROEventRepository, IROSessionsChangesListener)
private
fSessionIDs: TStringList;
// fEvents : TObjectList;
fCritical : TCriticalSection;
FDestroyed: Boolean;
function GetSessionReferenceCount: integer;
function GetSessionReferences(Index: integer): TROSessionReference;
procedure UnRegisterSessionsChangesListener;
procedure RegisterSessionsChangesListener;
protected
procedure SetSessionManager(const Value: TROCustomSessionManager); override;
function FindSession(aSessionID: TGUID): TROSessionReference;
{ Overrides }
procedure DoStoreEventData(SourceSessionID : TGUID; Data : Binary;
const ExcludeSender: Boolean;
const ExcludeSessionList: Boolean;
const SessionList: String); override;
function DoGetEventData(SessionID : TGUID; var TargetStream : Binary) : integer; override;
procedure DoAddSession(aSessionID: TGUID); overload; override;
procedure DoAddSession(aSessionID : TGUID; aActiveEventServer: IROActiveEventServer); overload; override;
procedure DoRemoveSession(aSessionID: TGUID); override;
procedure RemoveSessionActiveListener(aSessionID: TGUID);
procedure Loaded; override;
{ IROSessionsChangesListener }
procedure SessionsChangedNotification(const aSessionID : TGUID; aSessionAction: TROSessionsActions; Sender: TObject);
public
// procedure DeleteEventData(anEvent: TROEventData); override;
procedure BeforeDestruction; override;
constructor Create(aOwner : TComponent); override;
destructor Destroy; override;
property SessionReferences[Index : integer] : TROSessionReference read GetSessionReferences;
property SessionReferenceCount : integer read GetSessionReferenceCount;
published
end;
TROOnEventExceptionEvent = procedure (Sender: TObject; anException: Exception) of object;
IROEventReceiverInvokers = interface
['{C8EA6D75-562E-4FE5-B4EF-47ACD4D2ADE8}']
function Invoke_GetEventsData(out EventsData: Binary): Integer;
procedure Invoke_RegisterEventClient(const EventTypes: String);
procedure Invoke_UnregisterEventClient(const EventTypes: String);
end;
{ TROEventReceiver }
TROEventReceiver = class(TROChannelAwareComponent, IROObjectRetainer, IROEventReceiver, IROEventReceiverInvokers)
private
fTimer : TROThreadTimer;
fActive: boolean;
fServiceName: string;
fHandlers : TStringList;
fOnActivate: TNotifyEvent;
fOnDeactivate: TNotifyEvent;
fOnPollException: TROOnEventExceptionEvent;
fRetainedObjects : TList;
fInterval: Integer;
fEventAwareChannel: IROActiveEventChannel;
fSynchronizeInvoke: Boolean;
procedure SetInterval(const Value: integer);
procedure SetActive(const Value: boolean);
procedure SetServiceName(const Value: string);
function GetClientID: TGUID;
function GetSynchronizeInvoke: Boolean;
protected
function GetObject: TObject;
procedure FireEvents(EventsDataStream: TStream); virtual;
// Proxy methods
function Invoke_GetEventsData(out EventsData: Binary): Integer;
procedure Invoke_RegisterEventClient(const EventTypes: String);
procedure Invoke_UnregisterEventClient(const EventTypes: String);
procedure OnTimerTick(Dummy: Cardinal);
procedure Dispatch(aStream: TStream; aCaller: TThread); reintroduce;
public
constructor Create(aOwner : TComponent); override;
destructor Destroy; override;
procedure Activate;
procedure Deactivate;
procedure RegisterEventHandlers(const EventIDs : array of string; const EventHandlers : array of TObject); overload;
procedure RegisterEventHandler(const EventID : string; const EventHandler : TObject);
procedure UnregisterEventHandlersByObject(const EventHandler : array of TObject);
procedure UnregisterEventHandlers(const EventIDs : array of string); overload;
procedure UnregisterEventHandler(const EventHandler : TObject); overload;
procedure UnregisterEventHandler(const EventIDs : string); overload;
function EventHandlersIsRegistered(const EventIDs: array of string; const EventHandlers: array of TObject): boolean; deprecated;
function AreEventHandlersRegistered(const aEventIDs: array of string; const aEventHandlers: array of TObject): boolean;
function IsEventHandlerRegistered(const aEventID: string; const aEventHandler: TObject): boolean;
procedure CheckProperties;
{ IROObjectRetainer }
procedure RetainObject(const anObject : TObject);
procedure ReleaseObject(const anObject : TObject);
function IsRetained(const anObject : TObject) : boolean;
property ClientID : TGUID read GetClientID;
published
property Active : boolean read fActive write SetActive default false;
property Interval : integer read fInterval write SetInterval default 30000;
property Message;
property Channel;
property OnPollException: TROOnEventExceptionEvent read fOnPollException write fOnPollException;
property OnActivate : TNotifyEvent read fOnActivate write fOnActivate;
property OnDeactivate : TNotifyEvent read fOnDeactivate write fOnDeactivate;
property ServiceName : string read fServiceName write SetServiceName;
property SynchronizeInvoke: Boolean read GetSynchronizeInvoke write fSynchronizeInvoke default true;
end;
{ TROEventProxy }
TROEventProxy = class(TInterfacedObject)
private
fMessage : IROMessage;
function GetMessage: IROMessage;
protected
property __Message : IROMessage read GetMessage;
public
constructor Create(const aMessage : IROMessage; CloneMessage : boolean);
destructor Destroy; override;
end;
{ TROEventWriter }
TROEventWriter = class(TROEventProxy, IROEventWriter)
private
fRepository : IROEventRepository;
fExcludeSender: boolean;
fExcludeSessionList: boolean;
fSessionList: TStringList;
function GetRepository: IROEventRepository;
protected
property Repository : IROEventRepository read GetRepository;
{ IROEventWriter }
function GetSessionList: TStrings;
function GetExcludeSender: boolean;
function GetExcludeSessionList: boolean;
procedure SetExcludeSender(const Value: boolean);
procedure SetExcludeSessionList(const Value: boolean);
public
constructor Create(const aMessage : IROMessage;
const aRepository : IROEventRepository); reintroduce;
destructor Destroy; override;
property ExcludeSender : boolean read GetExcludeSender write SetExcludeSender;
property ExcludeSessionList : boolean read GetExcludeSessionList write SetExcludeSessionList;
property SessionList : TStrings read GetSessionList;
end;
TROEventWriterClass = class of TROEventWriter;
{ TROEventInvoker }
{$M+}
TROEventInvoker = class(TROEventProxy, IROEventsInvoker)
private
fEventReceiver : TROEventReceiver;
protected
{ IROEventsInvoker }
procedure Execute(const aTarget : TObject; EventData: TStream);
property __EventReceiver : TROEventReceiver read fEventReceiver;
public
constructor Create(anEventReceiver : TROEventReceiver;
const aMessage : IROMessage; CloneMessage : boolean); reintroduce;
destructor Destroy; override;
end;
{$M-}
TROEventInvokerClass = class of TROEventInvoker;
procedure RegisterEventWriterClass(const anEventIID : TGUID; anEventWriteClass : TROEventWriterClass);
procedure UnregisterEventWriterClass(const anEventIID : TGUID);
function FindEventWriterClass(const anEventIID : TGUID) : TROEventWriterClass;
procedure RegisterEventInvokerClass(const anEventID : string; anEventWriteClass : TROEventInvokerClass);
procedure UnregisterEventInvokerClass(const anEventID : string);
function FindEventInvokerClass(const anEventID : string) : TROEventInvokerClass;
implementation
uses
uRORes;
var
_EventInvokers,
_EventWriters : TStringList;
procedure RegisterEventWriterClass(const anEventIID : TGUID; anEventWriteClass : TROEventWriterClass);
var id : string;
begin
id := GUIDToString(anEventIID);
_EventWriters.AddObject(id, TObject(anEventWriteClass));
end;
procedure UnregisterEventWriterClass(const anEventIID : TGUID);
var idx : integer;
begin
idx := _EventWriters.IndexOf(GUIDToString(anEventIID));
if (idx>=0)
then _EventWriters.Delete(idx);
end;
function FindEventWriterClass(const anEventIID : TGUID) : TROEventWriterClass;
var idx : integer;
id : string;
begin
result := NIL;
id := GUIDToString(anEventIID);
idx := _EventWriters.IndexOf(id);
if (idx>=0)
then result := TROEventWriterClass(_EventWriters.Objects[idx]);
end;
procedure RegisterEventInvokerClass(const anEventID : string; anEventWriteClass : TROEventInvokerClass);
begin
_EventInvokers.AddObject(anEventID, TObject(anEventWriteClass));
end;
procedure UnregisterEventInvokerClass(const anEventID : string);
var idx : integer;
begin
idx := _EventInvokers.IndexOf(anEventID);
if (idx>=0)
then _EventInvokers.Delete(idx);
end;
function FindEventInvokerClass(const anEventID : string) : TROEventInvokerClass;
var idx : integer;
begin
result := NIL;
idx := _EventInvokers.IndexOf(anEventID);
if (idx>=0)
then result := TROEventInvokerClass(_EventInvokers.Objects[idx]);
end;
{ TROEventRepository }
procedure TROEventRepository.AddSession(aSessionID: TGUID);
begin
CheckProperties;
if Assigned(fOnBeforeAddSession) then
fOnBeforeAddSession(Self, aSessionID);
DoAddSession(aSessionID);
if Assigned(fOnAfterAddSession) then
fOnAfterAddSession(Self, aSessionID);
end;
procedure TROEventRepository.AddSession(aSessionID: TGUID; aActiveEventServer: IROActiveEventServer);
begin
CheckProperties;
if Assigned(fOnBeforeAddSession) then
fOnBeforeAddSession(Self, aSessionID);
DoAddSession(aSessionID, aActiveEventServer);
if Assigned(fOnAfterAddSession) then
fOnAfterAddSession(Self, aSessionID);
end;
procedure TROEventRepository.RemoveSession(aSessionID: TGUID);
begin
CheckProperties;
if Assigned(fOnBeforeRemoveSession)
then fOnBeforeRemoveSession(Self, aSessionID);
DoRemoveSession(aSessionID);
if Assigned(fOnAfterRemoveSession)
then fOnAfterRemoveSession(Self, aSessionID);
end;
function TROEventRepository.GetEventData(SessionID: TGUID;
var TargetStream: Binary): integer;
begin
CheckProperties;
result := DoGetEventData(SessionID, TargetStream);
end;
procedure TROEventRepository.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited;
if (Operation<>opRemove) then Exit;
if (AComponent=fSessionManager) then fSessionManager := NIL
else if (AComponent=fMessage) then fMessage := NIL;
end;
function TROEventRepository.QueryInterface(const IID: TGUID; out Obj): HResult;
var eventwriterclass : TROEventWriterClass;
eventwriter : TROEventWriter;
id : string;
begin
result := inherited QueryInterface(IID, Obj);
if (result<>S_OK) then begin
id := GUIDToString(IID);
if (id='') then Exit;
eventwriterclass := FindEventWriterClass(IID);
if (eventwriterclass=NIL) then Exit;
CheckProperties;
eventwriter := eventwriterclass.Create(fMessage, Self);
if eventwriter.GetInterface(IID, Obj)
then result := S_OK
else eventwriter.Free;
end;
end;
procedure TROEventRepository.SetMessage(const Value: TROMessage);
begin
fMessage := Value;
if (fMessage<>NIL) then fMessage.FreeNotification(Self);
end;
procedure TROEventRepository.SetSessionManager(
const Value: TROCustomSessionManager);
begin
if (fSessionManager=Value) then Exit;
fSessionManager := Value;
if (fSessionManager<>NIL)
then fSessionManager.FreeNotification(Self);
end;
procedure TROEventRepository.StoreEventData(SourceSessionID : TGUID; Data : Binary;
const ExcludeSender: Boolean; const ExcludeSessionList: Boolean; const SessionList: String);
begin
CheckProperties;
DoStoreEventData(SourceSessionID, Data, ExcludeSender, ExcludeSessionList, SessionList);
end;
procedure TROEventRepository.DoAddSession(aSessionID: TGUID;
aActiveEventServer: IROActiveEventServer);
begin
DoAddSession(aSessionID);
end;
(*procedure TROEventRepository.DeleteEventData(anEvent: TROEventData);
begin
///
end;*)
procedure TROEventRepository.CheckProperties;
begin
// Check(SessionManager = nil, Name + '.SessionManager must be assigned.');
Check(Message = nil, Name + '.Message must be assigned.');
Message.CheckProperties;
end;
{ TROInMemoryEventRepository }
constructor TROInMemoryEventRepository.Create(aOwner: TComponent);
begin
inherited;
fCritical := TCriticalSection.Create;
// fEvents := TObjectList.Create(False); // cleaned up one by one
fSessionIDs := TStringList.Create;
fSessionIDs.Duplicates := dupIgnore;
fSessionIDs.Sorted := TRUE;
end;
destructor TROInMemoryEventRepository.Destroy;
var
i: Integer;
llink: TROSessionReference;
lItem, lnext: TROSessionRefToEventDataLink;
begin
FDestroyed:=True;
fCritical.Enter;
try
for i := fSessionIDs.Count -1 downto 0 do begin
llink := TROSessionReference(fSessionIDs.Objects[i]);
if llink = nil then continue;
lItem := llink.Head;
llink.Free;
while lItem <> nil do begin
if lItem.EventData <> nil then begin
if lItem.EventData.RemoveRef <= 0 then
// fEvents.Remove(lItem.EventData);
lItem.EventData.Free
end;
lnext := lItem.Next;
lItem.Free;
lItem := lNext;
end;
end;
finally
fCritical.Leave;
end;
FreeAndNIL(fSessionIDs);
// FreeAndNIL(fEvents);
FreeAndNIL(fCritical);
inherited;
end;
function TROInMemoryEventRepository.DoGetEventData(SessionID: TGUID;
var TargetStream: Binary): integer;
var sessionreference : TROSessionReference;
prevref,
currref : TROSessionRefToEventDataLink;
chunksize : integer;
begin
result := 0;
if FDestroyed then Exit;
fCritical.Enter;
try
sessionreference := FindSession(SessionID);
if (sessionreference=NIL) then Exit;
TargetStream.Write(result, SizeOf(result));
currref := sessionreference.Head;
if (currref<>NIL) then begin
repeat
currref.EventData.Data.Position := 0;
chunksize := currref.EventData.Data.Size;
TargetStream.Write(chunksize, SizeOf(chunksize));
TargetStream.CopyFrom(currref.EventData.Data, 0);
Inc(result);
prevref := currref;
currref := currref.Next;
if (prevref.EventData.RemoveRef=0)then begin
// fEvents.Remove(prevref.EventData);
prevref.EventData.Free;
end;
prevref.Free;
until (currref=NIL);
sessionreference.Head := NIL;
sessionreference.Tail := NIL;
end;
// Updates the event count
TargetStream.Position := 0;
TargetStream.Write(result, SizeOf(result));
TargetStream.Position := 0;
finally
fCritical.Leave;
end;
end;
procedure TROInMemoryEventRepository.DoStoreEventData(SourceSessionID : TGUID; Data : Binary;
const ExcludeSender: Boolean; const ExcludeSessionList: Boolean; const SessionList: String);
var newlink : TROSessionRefToEventDataLink;
newevent : TROEventData;
sessionref : TROSessionReference;
i : integer;
filteredsessionslist : TStringList;
isfiltered : boolean;
currsessionid : string;
begin
if FDestroyed then Exit;
filteredsessionslist := NIL;
isfiltered := SessionList<>'';
if isfiltered then begin
filteredsessionslist := TStringList.Create;
filteredsessionslist.Sorted := TRUE;
filteredsessionslist.Duplicates := dupIgnore;
filteredsessionslist.CommaText := SessionList;
end;
fCritical.Enter;
try
newevent := TROEventData.Create(Data);
try
for i := 0 to (SessionReferenceCount-1) do begin
sessionref := SessionReferences[i];
currsessionid := GUIDToString(sessionref.SessionID);
// Filters the sessions the message will go to
if isfiltered then begin
if ExcludeSessionList then begin
if (filteredsessionslist.IndexOf(currsessionid)>=0)
then Continue;
end
else begin
if not (filteredsessionslist.IndexOf(currsessionid)>=0)
then Continue;
end;
end;
if IsEqualGUID(sessionref.SessionID, SourceSessionID) and ExcludeSender
then Continue;
if sessionref.ActiveEventReference <> nil then begin
newevent.AddRef; // we don't want the event to be freed before we're done with it.
sessionref.ActiveEventReference.DispatchEvent(newevent, sessionref.SessionID, Self);
end
else begin
newlink := TROSessionRefToEventDataLink.Create(newevent, sessionref);
if (sessionref.Head=NIL)
then sessionref.Head := newlink;
if (sessionref.Tail<>NIL)
then sessionref.Tail.Next := newlink;
sessionref.Tail := newlink;
end;
end;
finally
if newevent.RemoveRef < 1 then
newevent.Free;
end;
finally
fCritical.Leave;
FreeAndNIL(filteredsessionslist);
end;
end;
procedure TROInMemoryEventRepository.DoRemoveSession(aSessionID: TGUID);
var
idx : integer;
sessionreference : TROSessionReference;
prevref,
currref : TROSessionRefToEventDataLink;
begin
if FDestroyed then Exit;
fCritical.Enter;
try
idx := fSessionIDs.IndexOf(GUIDToString(aSessionID));
if idx>=0 then begin
sessionreference := TROSessionReference(fSessionIDs.Objects[idx]);
currref := sessionreference.Head;
if (currref<>NIL) then begin
repeat
prevref := currref;
currref := currref.Next;
if (prevref.EventData.RemoveRef=0)
then
prevref.EventData.Free;
prevref.Free;
until (currref=NIL);
sessionreference.Head := NIL;
sessionreference.Tail := NIL;
end;
fSessionIDs.Objects[idx].Free;
fSessionIDs.Delete(idx);
end;
finally
fCritical.Leave;
end;
end;
procedure TROInMemoryEventRepository.DoAddSession(aSessionID: TGUID);
begin
DoAddSession(aSessionID, nil);
end;
function TROInMemoryEventRepository.GetSessionReferenceCount: integer;
begin
result := fSessionIDs.Count;
end;
function TROInMemoryEventRepository.GetSessionReferences(
Index: integer): TROSessionReference;
begin
result := TROSessionReference(fSessionIDs.Objects[Index]);
end;
function TROInMemoryEventRepository.FindSession(
aSessionID: TGUID): TROSessionReference;
var idx : integer;
begin
result := NIL;
idx := fSessionIDs.IndexOf(GUIDToString(aSessionID));
if (idx>=0)
then result := TROSessionReference(fSessionIDs.Objects[idx]);
end;
procedure TROInMemoryEventRepository.UnRegisterSessionsChangesListener;
var
Ref: IROSessionsChangesNotifier;
SelfRef: IROSessionsChangesListener;
begin
if GetInterface(IROSessionsChangesListener, SelfRef) then begin
if Assigned(fSessionManager) and
fSessionManager.GetInterface(IROSessionsChangesNotifier, ref) then begin
ref.UnRegisterSessionsChangesListener(SelfRef);
end;
end;
end;
procedure TROInMemoryEventRepository.RegisterSessionsChangesListener;
var
Ref: IROSessionsChangesNotifier;
SelfRef: IROSessionsChangesListener;
begin
if GetInterface(IROSessionsChangesListener, SelfRef) then begin
if Assigned(fSessionManager) and
fSessionManager.GetInterface(IROSessionsChangesNotifier, ref) then begin
ref.RegisterSessionsChangesListener(SelfRef);
end;
end;
end;
procedure TROInMemoryEventRepository.SetSessionManager(
const Value: TROCustomSessionManager);
begin
if (csDesigning in ComponentState) or (csLoading in ComponentState) then begin
inherited;
Exit;
end;
UnRegisterSessionsChangesListener;
inherited;
RegisterSessionsChangesListener;
end;
procedure TROInMemoryEventRepository.Loaded;
begin
inherited;
RegisterSessionsChangesListener;
end;
procedure TROInMemoryEventRepository.SessionsChangedNotification(
const aSessionID: TGUID; aSessionAction: TROSessionsActions; Sender: TObject);
var
idx: Integer;
lRef: IROActiveEventServer;
sessionreference: TROSessionReference;
begin
if FDestroyed then Exit;
if aSessionAction in [saDelete, saTmpSessionDelete] then
RemoveSession(aSessionID);
if aSessionAction = saRemoveActiveListener then begin
fCritical.Enter;
try
idx := fSessionIDs.IndexOf(GUIDToString(aSessionID));
if idx>=0 then begin
sessionreference := TROSessionReference(fSessionIDs.Objects[idx]);
if Supports(Sender, IROActiveEventServer, lref) then begin
sessionreference.ActiveEventReference := TIROActiveEventServerList.RemoveListener(sessionreference.ActiveEventReference, lRef);
end else
sessionreference.ActiveEventReference := nil;
end;
finally
fCritical.Leave;
end;
end;
end;
procedure TROInMemoryEventRepository.BeforeDestruction;
begin
UnRegisterSessionsChangesListener;
inherited;
end;
procedure TROInMemoryEventRepository.DoAddSession(aSessionID: TGUID;
aActiveEventServer: IROActiveEventServer);
var newsession : TROSessionReference;
idx: Integer;
begin
if FDestroyed then Exit;
fCritical.Enter;
try
idx := fSessionIDs.IndexOf(GUIDToString(aSessionID));
if idx < 0 then begin
newsession := TROSessionReference.Create(aSessionID);
if aActiveEventServer <> nil then begin
newsession.ActiveEventReference := TIROActiveEventServerList.AddListener(newsession.ActiveEventReference, aActiveEventServer);
aActiveEventServer.EventsRegistered(self, aSessionID);
end;
fSessionIDs.AddObject(GUIDToString(aSessionID), newsession);
end
else begin
newsession := TROSessionReference(fSessionIDs.Objects[idx]);
if aActiveEventServer <> nil then begin
newsession.ActiveEventReference := TIROActiveEventServerList.AddListener(newsession.ActiveEventReference, aActiveEventServer);
aActiveEventServer.EventsRegistered(self, aSessionID);
end;
end;
finally
fCritical.Leave;
end;
end;
procedure TROInMemoryEventRepository.RemoveSessionActiveListener(
aSessionID: TGUID);
var
idx : integer;
sessionreference : TROSessionReference;
begin
if FDestroyed then Exit;
fCritical.Enter;
try
idx := fSessionIDs.IndexOf(GUIDToString(aSessionID));
if idx>=0 then begin
sessionreference := TROSessionReference(fSessionIDs.Objects[idx]);
sessionreference.ActiveEventReference := nil;
end;
finally
fCritical.Leave;
end;
end;
(*
procedure TROInMemoryEventRepository.DeleteEventData(
anEvent: TROEventData);
begin
fCritical.Enter;
try
fEvents.Remove(anEvent);
finally
fCritical.Leave;
end;
end;
*)
{ TROSessionReference }
constructor TROSessionReference.Create(aSessionID: TGUID);
begin
inherited Create;
fSessionID := aSessionID;
end;
function TROSessionReference.GetHead: TROSessionRefToEventDataLink;
begin
Result := fHead;
end;
function TROSessionReference.GetTail: TROSessionRefToEventDataLink;
begin
Result := fTail;
end;
{ TROSessionRefToEventDataLink }
constructor TROSessionRefToEventDataLink.Create(
anEventDataItem: TROEventData; aSessionReference: TROSessionReference);
begin
inherited Create;
anEventDataItem.AddRef;
fEventData := anEventDataItem;
fSessionReference := aSessionReference;
end;
destructor TROSessionRefToEventDataLink.Destroy;
begin
inherited;
end;
{ TROEventReceiver }
constructor TROEventReceiver.Create(aOwner: TComponent);
begin
inherited;
fHandlers := TStringList.Create;
fInterval := 30000;
fSynchronizeInvoke := true;
end;
destructor TROEventReceiver.Destroy;
begin
FreeAndNIL(fHandlers);
FreeAndNIL(fRetainedObjects);
inherited;
end;
procedure TROEventReceiver.Activate;
begin
Active := TRUE;
end;
procedure TROEventReceiver.Deactivate;
begin
Active := FALSE;
end;
procedure TROEventReceiver.SetActive(const Value: boolean);
begin
if Value <> fActive then begin
if Value and not (csDesigning in ComponentState) then
CheckProperties;
fActive := Value;
if (Channel = nil) or not Supports(Channel, IROActiveEventChannel, fEventAwareChannel) then
fEventAwareChannel := nil;
if Value then
begin
if fEventAwareChannel <> nil then
fEventAwareChannel.RegisterEventReceiver(self)
else
if FTimer = nil then
fTimer := TROThreadTimer.Create(OnTimerTick, fInterval, false);
end else begin
if fEventAwareChannel <> nil then
fEventAwareChannel.UnregisterEventReceiver(self)
else
if fTimer <> nil then
begin
fTimer.AsyncFree;
fTimer := nil;
end;
end;
if Value then begin
if Assigned(fOnActivate) then fOnActivate(Self);
end
else begin
if Assigned(fOnDeactivate) then fOnDeactivate(Self);
end;
end;
end;
procedure TROEventReceiver.SetInterval(const Value: integer);
begin
fInterval := Value;
if fTimer <> nil then
fTimer.Timeout := Value;
end;
procedure TROEventReceiver.SetServiceName(const Value: string);
begin
fServiceName := Trim(Value);
end;
procedure TROEventReceiver.Invoke_RegisterEventClient(const EventTypes: String);
var
__message : IROMessage;
__channel : IROTransportChannel;
ClientId: string;
begin
CheckProperties;
__message := (Message as IROMessage);
__channel := (Channel as IROTransportChannel);
try
__message.InitializeRequestMessage(__channel, 'RemObjects', ServiceName, 'RegisterEventClient');
__channel.BeforeDispatch(__message); // sets the client id for some channels
ClientId := GuidToString(__message.ClientID);
__message.Write('ClientID', TypeInfo(String), ClientId, []);
__message.Write('EventTypes', TypeInfo(String), EventTypes, []);
__message.Finalize;
__channel.Dispatch(__message);
finally
__Message.FreeStream;
end
end;
procedure TROEventReceiver.Invoke_UnregisterEventClient(const EventTypes: String);
var
__message : IROMessage;
__channel : IROTransportChannel;
ClientId: string;
begin
CheckProperties;
__message := (Message as IROMessage);
__channel := (Channel as IROTransportChannel);
try
__message.InitializeRequestMessage(__channel, 'RemObjects', ServiceName, 'UnregisterEventClient');
__channel.BeforeDispatch(__message);
ClientId := GuidToString(__message.ClientID);
__message.Write('ClientID', TypeInfo(String), ClientID, []);
__message.Write('EventTypes', TypeInfo(String), EventTypes, []);
__message.Finalize;
__channel.Dispatch(__message);
finally
__Message.FreeStream;
end
end;
function TROEventReceiver.Invoke_GetEventsData(out EventsData: Binary): Integer;
var
__message : IROMessage;
__channel : IROTransportChannel;
ClientId: string;
begin
CheckProperties;
__message := (Message as IROMessage);
__channel := (Channel as IROTransportChannel);
try
__message.InitializeRequestMessage(__channel, 'RemObjects', ServiceName, 'GetEventsData');
__channel.BeforeDispatch(__message);
ClientId := GuidToString(__message.ClientID);
__message.Write('ClientID', TypeInfo(String), ClientID, []);
__message.Finalize;
__channel.Dispatch(__message);
__message.Read('Result', TypeInfo(Integer), result, []);
__message.Read('EventsData', TypeInfo(Binary), EventsData, []);
finally
__message.FreeStream;
end
end;
procedure TROEventReceiver.FireEvents(EventsDataStream : TStream);
var
tempstream : TStream;
chunksize, idx, cnt : integer;
messageclone : IROMessage;
eventInvokerclass : TROEventInvokerClass;
eventInvoker : TROEventInvoker;
begin
CheckProperties;
tempstream := NIL;
eventInvoker := NIL;
messageclone := (Message as IROMessageCloneable).Clone;
EventsDataStream.Position := 0;
if fEventAwareChannel <> nil then begin
// event aware channels send one event at a time.
messageclone.ReadFromStream(EventsDataStream);
eventInvokerclass := FindEventInvokerClass(messageclone.InterfaceName);
eventInvoker := eventInvokerclass.Create(Self, messageclone, FALSE);
try
for idx := 0 to fHandlers.Count -1 do begin
if SameText(fHandlers[idx], messageclone.InterfaceName) then
eventInvoker.Execute(fHandlers.Objects[idx], EventsDataStream);
end;
finally
FreeAndNIL(eventInvoker);
end;
end
else begin
EventsDataStream.Read(cnt, SizeOf(integer));
while (EventsDataStream.Position<EventsDataStream.Size-1) do try
EventsDataStream.Read(chunksize, SizeOf(integer));
tempstream := TMemoryStream.Create;
tempstream.CopyFrom(EventsDataStream, chunksize);
tempstream.Position := 0;
messageclone.ReadFromStream(tempstream);
eventInvokerclass := FindEventInvokerClass(messageclone.InterfaceName);
eventInvoker := eventInvokerclass.Create(Self, messageclone, FALSE);
try
for idx := 0 to fHandlers.Count -1 do begin
if SameText(fHandlers[idx], messageclone.InterfaceName) then
eventInvoker.Execute(fHandlers.Objects[idx], tempstream);
end;
finally
FreeAndNIL(eventInvoker);
end;
finally
tempstream.Free;
end;
end;
end;
procedure TROEventReceiver.OnTimerTick(Dummy: Cardinal);
var
eventsdata: Binary;
cnt : integer;
begin
if Channel.Busy then Exit;
CheckProperties;
eventsdata := NIL;
try
eventsdata := NIL;
try
cnt := Invoke_GetEventsData(eventsdata);
// Fires the events...
if (cnt>0) and (eventsdata<>NIL) then begin
Dispatch(eventsdata, fTimer);
end;
except
on e: Exception do
begin
if @fOnPollException <> nil then
fOnPollException(self, e);
end;
end;
finally
if (eventsdata<>NIL)
then eventsdata.Free;
end;
end;
procedure TROEventReceiver.RegisterEventHandlers(
const EventIDs: array of string;
const EventHandlers: array of TObject);
var clientid, eventID, eventtypes : string;
i : integer;
begin
// Adds a reference to the event handler object
clientid := GUIDTOString(Self.ClientID);
eventtypes := '';
for i := 0 to Length(EventIDs)-1 do begin
eventID := EventIDs[i];
eventtypes := eventtypes+eventID+',';
end;
Delete(eventtypes, Length(eventtypes), 1);
// Sends the remote request
if fEventAwareChannel = nil then
Invoke_RegisterEventClient(eventtypes);
//Moved here to avoid invalid list in case registration is incorrect.
//(for example if connection to server temporary broken)
for i := 0 to Length(EventIDs)-1 do begin
// Adds a reference to the local event handler object
eventID := EventIDs[i];
fHandlers.AddObject(eventID, EventHandlers[i]);
end;
end;
{$WARN SYMBOL_DEPRECATED OFF} // delphi warns on the implementation of this method because it's defined as deprecated.
function TROEventReceiver.EventHandlersIsRegistered(const EventIDs: array of string; const EventHandlers: array of TObject): boolean;
begin
result := AreEventHandlersRegistered(EventIDs, EventHandlers);
end;
{$WARN SYMBOL_DEPRECATED ON}
function TROEventReceiver.AreEventHandlersRegistered(const aEventIDs: array of string; const aEventHandlers: array of TObject): boolean;
var
i : integer;
begin
Result := True;
for i := 0 to Length(aEventIDs) - 1 do begin
if not IsEventHandlerRegistered(aEventIDs[i], aEventHandlers[i]) then begin
Result := False;
break;
end;
end;
end;
function TROEventReceiver.IsEventHandlerRegistered(const aEventID: string; const aEventHandler: TObject): boolean;
var
j : integer;
begin
Result := False;
for j := 0 to fHandlers.Count - 1 do
if (fHandlers.Objects[j] = aEventHandler) and (fHandlers[j] = aEventID) then begin
Result := True;
break;
end;
end;
procedure TROEventReceiver.UnregisterEventHandlers(const EventIDs: array of string);
var clientid, eventID, eventtypes : string;
i, idx : integer;
begin
clientid := GUIDTOString(Self.ClientID);
eventtypes := '';
for i := 0 to Length(EventIDs)-1 do begin
eventID := EventIDs[i];
// Removes the reference to the local event handler object
idx := fHandlers.IndexOf(eventID);
if (idx>=0)
then fHandlers.Delete(idx);
eventtypes := eventtypes+eventID+',';
end;
Delete(eventtypes, Length(eventtypes), 1);
// Sends the remote request
if fEventAwareChannel = nil then
Invoke_UnregisterEventClient(eventtypes);
end;
function TROEventReceiver.GetClientID: TGUID;
begin
CheckProperties;
result := Message.ClientID;
end;
function TROEventReceiver.IsRetained(const anObject: TObject): boolean;
begin
result := (fRetainedObjects<>NIL) and (fRetainedObjects.IndexOf(anObject)>=0)
end;
procedure TROEventReceiver.ReleaseObject(const anObject: TObject);
var idx : integer;
begin
// Only creates it if necessary
if (fRetainedObjects=NIL) then Exit;
idx := fRetainedObjects.IndexOf(anObject);
if (idx>=0) then fRetainedObjects.Delete(idx);
end;
procedure TROEventReceiver.RetainObject(const anObject: TObject);
begin
// Only creates it if necessary
if (fRetainedObjects=NIL) then
fRetainedObjects := TList.Create;
fRetainedObjects.Add(anObject);
end;
type
TMyThread = class(TThread) end; // in d6 a thread is private
TSyncClass = class
private
fData: TStream;
fCaller: TROEventReceiver;
public
property Caller: TROEventReceiver read fCaller write fCaller;
property Data: TStream read fData write fData;
procedure DoDispatch;
end;
procedure TSyncClass.DoDispatch;
begin
fCaller.FireEvents(Data);
end;
procedure TROEventReceiver.Dispatch(aStream: TStream; aCaller: TThread);
var
lSync: TSyncClass;
begin
if fSynchronizeInvoke and Assigned(aCaller) then
begin
lSync := TSyncClass.Create;
try
lSync.Caller := Self;
lSync.Data := aStream;
TMyThread(aCaller).Synchronize(lSync.DoDispatch);
finally
lSync.Free;
end;
end else
FireEvents(aStream);
end;
function TROEventReceiver.GetSynchronizeInvoke: Boolean;
begin
Result := fSynchronizeInvoke;
end;
procedure TROEventReceiver.RegisterEventHandler(const EventID: string;
const EventHandler: TObject);
begin
RegisterEventHandlers([EventID], [EventHandler]);
end;
procedure TROEventReceiver.UnregisterEventHandlersByObject(
const EventHandler: array of TObject);
var clientid, eventID, eventtypes : string;
i, idx : integer;
begin
clientid := GUIDTOString(Self.ClientID);
eventtypes := '';
for i := 0 to Length(EventHandler)-1 do begin
// Removes the reference to the local event handler object
idx := fHandlers.IndexOfObject(EventHandler[i]);
if (idx>=0)
then begin
eventID := fHandlers[i];
fHandlers.Delete(idx)
end else continue;
eventtypes := eventtypes+eventID+',';
end;
Delete(eventtypes, Length(eventtypes), 1);
// Sends the remote request
// if fEventAwareChannel = nil then
Invoke_UnregisterEventClient(eventtypes);
end;
procedure TROEventReceiver.UnregisterEventHandler(
const EventHandler: TObject);
begin
UnregisterEventHandlersByObject([EventHandler]);
end;
procedure TROEventReceiver.UnregisterEventHandler(const EventIDs: string);
begin
UnregisterEventHandlers([EventIDs]);
end;
procedure TROEventReceiver.CheckProperties;
begin
Check(Channel = nil, Name + '.Channel must be assigned.');
Channel.CheckProperties;
Check(Message = nil, Name + '.Message must be assigned.');
Message.CheckProperties;
Check(ServiceName = '', Name + '.ServiceName must be set.');
end;
function TROEventReceiver.GetObject: TObject;
begin
result := Self;
end;
{ TROEventWriter }
constructor TROEventWriter.Create(const aMessage : IROMessage;
const aRepository : IROEventRepository);
begin
inherited Create(aMessage, TRUE);
fSessionList := TStringList.Create;
fSessionList.Sorted := TRUE;
fSessionList.Duplicates := dupIgnore;
fExcludeSender := TRUE;
fExcludeSessionList := FALSE; // By default only includes those in the session list
fRepository := aRepository;
end;
destructor TROEventWriter.Destroy;
begin
fRepository := NIL;
FreeAndNIL(fSessionList);
inherited;
end;
{function TROEventWriter.GetMessage: IROMessage;
begin
result := fMessage;
end;}
function TROEventWriter.GetExcludeSender: boolean;
begin
result := fExcludeSender
end;
function TROEventWriter.GetExcludeSessionList: boolean;
begin
result := fExcludeSessionList;
end;
function TROEventWriter.GetRepository: IROEventRepository;
begin
result := fRepository
end;
function TROEventWriter.GetSessionList: TStrings;
begin
result := fSessionList;
end;
procedure TROEventWriter.SetExcludeSender(const Value: boolean);
begin
fExcludeSender := Value
end;
procedure TROEventWriter.SetExcludeSessionList(const Value: boolean);
begin
fExcludeSessionList := Value
end;
{ TROEventProxy }
constructor TROEventProxy.Create(const aMessage: IROMessage; CloneMessage: boolean);
begin
inherited Create;
if CloneMessage then begin
if (aMessage=NIL) then raise EROException.Create(err_MessageNotAssigned);
fMessage := (aMessage as IROMessageCloneable).Clone
end
else fMessage := aMessage;
end;
destructor TROEventProxy.Destroy;
begin
fMessage := NIL;
inherited;
end;
function TROEventProxy.GetMessage: IROMessage;
begin
result := fMessage
end;
{ TROEventInvoker }
constructor TROEventInvoker.Create(anEventReceiver: TROEventReceiver;
const aMessage: IROMessage; CloneMessage: boolean);
begin
inherited Create(aMessage, CloneMessage);
fEventReceiver := anEventReceiver;
end;
destructor TROEventInvoker.Destroy;
begin
inherited;
end;
procedure TROEventInvoker.Execute(const aTarget : TObject; EventData: TStream);
var mtd : TROInvokerInvokeMethod;
intf : IInterface;
begin
__Message.ReadFromStream(EventData);
mtd := nil;
@mtd := MethodAddress('Invoke_'+__Message.MessageName);
if (@mtd <> nil) then begin
aTarget.GetInterface(IInterface, intf);
mtd(__EventReceiver, __Message, intf);
end;
end;
{ TSyncClass }
{ TIROActiveEventServerList }
class function TIROActiveEventServerList.AddListener(
aList: IROActiveEventServerList;
aItem: IROActiveEventServer): IROActiveEventServerList;
begin
result := aList;
while aList <> nil do begin
if aList.Server = aItem then exit;
aList := aList.Next;
end;
Result := TIROActiveEventServerList.Create(Result, aItem);
end;
constructor TIROActiveEventServerList.Create(
aNext: IROActiveEventServerList; aItem: IROActiveEventServer);
begin
inherited Create;
fNext := aNext;
fServer := aItem;
end;
procedure TIROActiveEventServerList.DispatchEvent(
anEventDataItem: TROEventData; aSessionReference: TGUID;
aSender: TObject);
var
lItem: IROActiveEventServerList;
begin
lItem := Self;
while lItem <> nil do begin
lItem.Server.DispatchEvent(anEventDataItem, aSessionReference, aSender);
lItem := lItem.Next;
if lItem <> nil then
anEventDataItem.AddRef;
end;
end;
function TIROActiveEventServerList.GetNext: IROActiveEventServerList;
begin
result := fNext;
end;
function TIROActiveEventServerList.GetServer: IROActiveEventServer;
begin
result := fServer;
end;
class function TIROActiveEventServerList.RemoveListener(
aList: IROActiveEventServerList; aItem: IROActiveEventServer): IROActiveEventServerList;
var
lPrev: IROActiveEventServerList;
begin
lPrev := nil;
result := aList;
while aList <> nil do begin
if aList.Server = aItem then begin
if lPrev = nil then begin
result := aList.Next;
exit;
end else begin
lPrev.Next := aList.Next;
end;
end;
aList := aList.Next;
end;
end;
procedure TIROActiveEventServerList.SetNext(
aData: IROActiveEventServerList);
begin
fNext := aData;
end;
initialization
_EventInvokers := TStringList.Create;
_EventInvokers.Sorted := TRUE;
_EventInvokers.Duplicates := dupIgnore;
_EventWriters := TStringList.Create;
_EventWriters.Sorted := TRUE;
_EventWriters.Duplicates := dupIgnore;
finalization
FreeAndNIL(_EventInvokers);
FreeAndNIL(_EventWriters);
end.