Event broker

Purpose

 * To allow event driven programming
 * To have loose coupling between classes
 * A (partial) implementation of the Observer pattern

Download
SysEventBroker.xpo (11 KB)

Implementaion
Three classes are provided:


 * 1) SysEventListener is the interface class for a "listener"
 * 2) * gotEvent: every listener must implement
 * 3) SysEventInfo is an implementation for a listener, which simply put received information on the Infolog
 * 4) * main: contains a simple test case
 * 5) SysEventBroker, which client classes use to register and notify listeners, it implements the following methods:
 * 6) * addListener: to register a listener
 * 7) * removeListener: to unregister a listener
 * 8) * fireEvent: to fire an event and to notify listeners via the gotEvent method

Example
static void SysEventTest(Args _args) {   SysEventBroker broker = SysEventBroker::construct; SysEventInfo  info1  = new SysEventInfo("Info-1"); // catch all; SysEventInfo  info2  = new SysEventInfo("Info-2"); // catch specific class SysEventInfo  info3  = new SysEventInfo("Info-3"); // catch specific type ;   // Setup broker.addListener(info1, classNum(Object)); broker.addListener(info2, classNum(Runbase)); broker.addListener(info3, classNum(Object), "Fire 2"); // catch Fire 2 broker.addListener(info3, classNum(Object), "Fire 4"); // and Fire 4

broker.fireEvent(classNum(CustAutoCreate), "Fire 1", "This is my life"); broker.removeListener(info2, classNum(Runbase)); broker.fireEvent(classNum(CustAutoCreate), "Fire 2", "this is my time"); broker.fireEvent(classNum(CustAutoCreate), "Fire 3", "just show me the light"); broker.removeListener(info1); broker.fireEvent(classNum(CustAutoCreate), "Fire 4", "and I go there"); } Generated info: Info-2 CustAutoCreate(Fire 1): This is my life Info-1 CustAutoCreate(Fire 1): This is my life Info-3 CustAutoCreate(Fire 2): this is my time Info-1 CustAutoCreate(Fire 2): this is my time Info-1 CustAutoCreate(Fire 3): just show me the light Info-3 CustAutoCreate(Fire 4): and I go there

Explanation
An event broker and 3 event listeners are created. The event listeners are then registered with broker.addListener which takes 3 arguments:


 * 1) Listener object: identifying the listener object
 * 2) Class id: identifying the sender class which the listener is interested in
 * 3) Event type: an optional string identifying the event to listen to (all events if not given)

Then events are fired with broker.fireEvent which as parameter takes 3 arguments:


 * 1) Class id: identifying the sender class
 * 2) Event type: a string identifying the event
 * 3) data: any additional information which can have any type

In the first fireEvent the class id is SalesAutoCreate (it is a lie), the event type is "Fire 1" and the data is the first line of a song. As SalesAutoCreate has parent class RunBase and Object both info1 and info2 listeners receive the gotEvent call, and the first two lines of info is generated. The info3 listener does not get the event, it is interested in "Fire 2" and "Fire 4" events only.

It is unusual to have addListener and fireEvent in the same method. A more interesting way would be for a top level class to implement gotEvent, call addListener(this, classNum(SomeClass)), then deep down the call stack SomeClass will call fireEvent.

Global broker
Client classes need to share a SysEventBroker instance. A possible solution is to use the global Infolog object.

In the Info.classDeclaration add: SysEventBroker eventBroker;

Add a new method: public SysEventBroker eventBroker {   if (!eventBroker) eventBroker = SysEventBroker::construct; return eventBroker; }

Beware, Infolog lives at the client, all notified infomation is sent to the client.

You could make the same implementation in the Application class which lives at the server. But you must then remember to use the same broker.

Warning
This is no silver bullet, do not abuse!
 * Do not not use when standard method calls and argument passing is the easy solution.
 * Do not forget to unregister the listener, even if an exception is thrown. Use try/catch!
 * Registered listeners live as long as the broker, if it is Infolog.eventBroker for the entire user session!