Axaptapedia is now maintained by AgileCadence For more information please click here.
Event broker
Contents
Purpose[edit]
- To allow event driven programming
- To have loose coupling between classes
- A (partial) implementation of the Observer pattern
Download[edit]
Implementaion[edit]
Three classes are provided:
- SysEventListener is the interface class for a "listener"
- gotEvent: every listener must implement
- SysEventInfo is an implementation for a listener, which simply put received information on the Infolog
- main: contains a simple test case
- SysEventBroker, which client classes use to register and notify listeners, it implements the following methods:
- addListener: to register a listener
- removeListener: to unregister a listener
- fireEvent: to fire an event and to notify listeners via the gotEvent method
Example[edit]
<xpp> 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");
} </xpp> Generated info: <xpp> 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 </xpp>
Explanation[edit]
An event broker and 3 event listeners are created. The event listeners are then registered with broker.addListener which takes 3 arguments:
- Listener object: identifying the listener object
- Class id: identifying the sender class which the listener is interested in
- 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:
- Class id: identifying the sender class
- Event type: a string identifying the event
- 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[edit]
Client classes need to share a SysEventBroker instance. A possible solution is to use the global Infolog object.
In the Info.classDeclaration add: <xpp>
SysEventBroker eventBroker;
</xpp>
Add a new method: <xpp> public SysEventBroker eventBroker() {
if (!eventBroker) eventBroker = SysEventBroker::construct(); return eventBroker;
} </xpp>
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[edit]
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!
See also[edit]
Another solution on Issues concerning X++