Publish/Subscribe communication between plugins via the EventBroker.
EventBrokerDemo.exe
| DCC_UsePackage = rtl;fmx;FMXPluginFramework
|
+-- Register TEventBroker
+-- TBPLLoader.LoadAll(plugins.json)
|
+-- PluginAlpha.bpl -> subscribed to 'alpha' + 'broadcast'
+-- PluginBeta.bpl -> subscribed to 'beta' + 'broadcast'
+-- PluginGamma.bpl -> subscribed to 'gamma' + 'broadcast'
+-- PluginAndromeda.bpl -> subscribed to 'andromeda' + 'andromeda.show' + 'broadcast'
|
+-- MainForm: Buttons publish topics
+-- Alpha / Beta / Gamma / Andromeda -> targeted topic
+-- Open Andromeda -> 'andromeda.show'
+-- Broadcast -> all plugins react
- IEventBroker: Publish/Subscribe for loose plugin coupling
- Sender info via AData:
TStringListwithValues['sender']as context - 4 plugins with frames: Each plugin displays received events in its own TMemo
- Broadcast pattern: A topic that reaches all plugins simultaneously
- Ring pattern: Plugins can react to events from other plugins
| File | Purpose |
|---|---|
EventBrokerDemo.dpr |
Host app with EventBroker registration |
Source/uMain.pas + .fmx |
MainForm with buttons + plugin frames side by side |
EventBrokerDemo.groupproj |
Build: Framework -> 4 Plugins -> App |
plugins.json |
Plugin list (Alpha, Beta, Gamma, Andromeda) |
../DemoPlugins/PluginAlpha/ |
Plugin with frame + EventBroker subscriber |
../DemoPlugins/PluginBeta/ |
Plugin with frame + EventBroker subscriber |
../DemoPlugins/PluginGamma/ |
Plugin with frame + EventBroker subscriber |
../DemoPlugins/PluginAndromeda/ |
Plugin with frame + EventBroker subscriber |
- Host registers
TEventBrokerasIEventBrokerservice - Plugins subscribe to their topics in
Initialize - Buttons in the MainForm publish topics with sender info
- Plugins receive events and log them in their frames
- Shutdown:
ClearAll->UnloadAll->ReleaseInstance
IEventBroker = interface
procedure Subscribe(const ATopic: string; const ACallback: TEventCallback);
procedure Unsubscribe(const ATopic: string; const ACallback: TEventCallback);
procedure Publish(const ATopic: string; const AData: TObject = nil);
end;procedure TMyPlugin.Initialize;
var Svc: IInterface;
begin
if TServiceRegistry.Instance.GetService(IEventBroker, Svc) then
(Svc as IEventBroker).Subscribe('my.topic', HandleEvent);
end;var
Data: TStringList;
begin
Data := TStringList.Create;
try
Data.Values['sender'] := 'MyPlugin';
EventBroker.Publish('my.topic', Data);
finally
Data.Free;
end;
end;Callbacks are collected inside the lock, then invoked outside the lock. This means:
- A subscriber can safely unsubscribe from within its own callback
- One failing callback doesn't block others
- No deadlocks from re-entrant calls