3D PLM Enterprise Architecture |
Middleware Abstraction |
The Callback MechanismMaking objects collaborate |
Use Case |
AbstractThis article shows how to set callbacks, that is, how to subscribe or listen to events, and how to publish events to the subscribers or listeners. |
This use case is intended to show you how the callback mechanism [1] works.
[Top]
CAASysCallback is a use case of the CAASystem.edu framework that illustrates System framework capabilities.
[Top]
This use case shows how to implement the publish/subscribe design pattern using the example of an event publisher played by an alarm that can ring, and an event subscriber or listener played by a burglar that approaches a place when there is something to steal, but fortunately protected by an alarm. The alarm ringing makes the burglar run away.
This article deals with one of the scenarios of CAASysCallback. You can refer to the module to see the others.
[Top]
To launch CAASysCallback, you will need to set up the build time environment, then compile CAASysCallback along with its prerequisites, set up the run time environment, and then execute the use case [2].
[Top]
The CAASysCallback use case is made of a several classes located in the CAASysCallback.m module of the CAASystem.edu framework:
Windows | InstallRootDirectory\CAASystem.edu\CAASysCallback.m\ |
Unix | InstallRootDirectory/CAASystem.edu/CAASysCallback.m/ |
where InstallRootDirectory
is the directory where the CAA CD-ROM
is installed.
[Top]
To create an event publisher, an event subscriber or listener, and a scenario to make them play together, there are four steps:
# | Step | Where |
---|---|---|
1 | Creating an Event | CAASysRingingNotification class |
2 | Creating an Event Publisher | CAASysAlarm class |
3 | Creating an Event Subscriber or Listener | CAASysBurglar class |
4 | Create a Publish/Subscribe Scenario | CAASysScenario.cpp file |
[Top]
The event to create is the ringing of the alarm. It is created as a notification class that the alarm class will then instantiate and publish. Its header file is as follows:
#include "CATNotification.h" class CAASysRingNotification : public CATNotification { CATDeclareClass; public: CAASysRingNotification(); virtual ~CAASysRingNotification(); private: CAASysRingNotification(const CAASysRingNotification &iObjectToCopy); }; |
This class simply derives from CATNotification. The CATDeclareClass
macro makes CAASysRingNotification part of a component. The copy
constructor is set as private and is not implemented to prevent the compiler to
create one as public, and thus prevent from illegal copies of the notification
instances.
#include "CAASysRingNotification.h" CATImplementClass(CAASysRingNotification, Implementation, CATBaseUnknown, CATNull); ... |
The CATImplementClass
macro declares that CAASysRingNotification
is an Implementation
, that is, a component main class, that
OM-derives from CATBaseUnknown. The last argument must always be set to CATNull
if the second one is set to Implementation
.
... CAASysRingNotification::CAASysRingNotification() {} CAASysRingNotification::~CAASysRingNotification() {} |
The CAASysRingNotification class constructor use the default constructor of the CATNotification class.
... CATNotification(int iAutomaticDelete=CATNotificationDeleteOff); ... |
It means that the iAutomaticDelete
value is CATNotificationDeleteOff
,
and consequently the notification must be deleted by those which have created
it. You can read the referenced article for a comparison between the callback
and send/receive mechanism about the CATNotification class creation and
usage [3].
[Top]
The alarm class header file is as follows:
#include "CATBaseUnknown.h" class CAASysAlarm: public CATBaseUnknown { CATDeclareClass; public: CAASysAlarm(char * iAlarmPlaceName); virtual ~CAASysAlarm(); void StartRinging(); char *GetPlace(); private: CAASysAlarm (); CAASysAlarm(const CAASysAlarm &iObjectToCopy); private: char * _pAlarmPlaceName; }; |
The method StartRinging
is the publishing method for the CAASysRingNotification
instances.
#include "CAASysAlarm.h" #include "CAASysRingNotification.h" #include "CATCallbackManager.h" CATImplementClass(CAASysAlarm, Implementation, CATBaseUnknown, CATNull); CAASysAlarm::CAASysAlarm(char * iAlarmPlaceName) { ... // Creates the data member: the place where the alarm will ring } CAASysAlarm::~CAASysAlarm() { ... // Deletes the data member } ... |
The constructor simply instantiates the data member, and the destructor deletes it.
... void CAASysAlarm::StartRinging() { CATCallbackManager * pCBManager = ::GetDefaultCallbackManager(this) ; if ( NULL != pCBManager ) { CAASysRingNotification * pNotification = new CAASysRingNotification(); pCBManager->DispatchCallbacks(pNotification, this); pNotification->Release(); pNotification = NULL ; } } ... |
The StartRinging
method publishes the notification that states
that the alarm is ringing. To do this, the global function GetDefaultCallbackManager
retrieves the callback manager associated by default with the alarm class
instance, and this callback uses its DispatchCallbacks
method to
inform its subscribers or listeners that the alarm is ringing by means of the CAASysRingNotification
notification created.
You can note that the CAASysRingNotification
class instance is deleted just after the DispatchCallbacks
call
such as explained in the CAASysRingNotification
class constructor.
[Top]
The event subscriber or listener is the burglar class. Its header file is as follows:
#include "CATBaseUnknown.h" #include "CATEventSubscriber.h" class CAASysAlarm; class CAASysBurglar: public CATBaseUnknown { public: CAASysBurglar(char * iBurglarName); virtual ~CAASysBurglar(); void Approach(CAASysAlarm *iAlarm); void RunAway (CATCallbackEvent iEventAlarm, void *iAlarm, CATNotification *iNotifAlarm, CATSubscriberData iBurglarData, CATCallback iCallBack); private: CAASysBurglar (); CAASysBurglar(const CAASysBurglar &iObjectToCopy); private: CAASysAlarm * _pAlarm; char * _pBurglarName; }; |
The Approach
method sets the callback and the RunAway
method is the callback method, that is, is called when the event referred to by
the Approach
method happens.
The burglar source file is as follows:
... CAASysBurglar::~CAASysBurglar() { if ( NULL != _pAlarm) { ::RemoveSubscriberCallbacks(this, _pAlarm); _pAlarm=NULL; }; ... // delete the data member } ... |
The destructor uses the global function RemoveSubscriberCallbacks
to remove the callbacks set by the CAASysBurglar class instance for the CAASysAlarm
notification.
The Approach
method that sets the callback is as follows:
... void CAASysBurglar::Approach(CAASysAlarm *iAlarm) { if ( iAlarm != _pAlarm ) { if ( NULL != _pAlarm) { ::RemoveSubscriberCallbacks(this, _pAlarm); }; _pAlarm=iAlarm; if ( NULL != iAlarm ) { CATCallback idCB ; idCB = ::AddCallback(this, iAlarm, "CAASysRingNotification", (CATSubscriberMethod)&CAASysBurglar::RunAway, NULL); } } }... |
Approach
begins by removing possible callbacks set by the CAASysBurglar
class instance for the CAASysAlarm notification, and then uses the global
function AddCallback
to set the callback. AddCallback
has the following parameters:
this |
The event subscriber or listener |
iAlarm |
The event publisher to subscribe to, or listen |
CAASysRingNotification |
The notification that represents the event |
(CATSubscriberMethod)&CAASysBurglar::RunAway |
The method to call back whenever the event happens |
NULL |
Possible useful data for the RunAway method |
The callback method RunAway
is as follows:
... void CAASysBurglar::RunAway(CATCallbackEvent iEventAlarm, void *iAlarm, CATNotification *iNotifAlarm, CATSubscriberData iBurglarData, CATCallback iCallBack) { CAASysAlarm *AlarmIsRinging = (CAASysAlarm *)iAlarm; printf("Burglar %s run away %s and very quickly.\n", _pBurglarName, AlarmIsRinging->GetPlace()); } |
Its signature has the following parameters:
iEventAlarm |
The published event |
iAlarm |
The event publisher |
iNotifAlarm |
The notification that represents the event |
iBurglarData |
Possible useful data for the RunAway method |
iCallBack |
The callback identifier |
RunAway
is dedicated to the action to undertake when the alarm
begins ringing. This action is up to you. It's limited here to a trace.
[Top]
The following scenario creates an event publisher Alarm
, and an
event subscriber or listener Burglar
. The burglar approaches the
place where Alarm
is active, and sets a callback on this object.
Then Alarm
rings.
... int main() { cout << endl << "The CAASysCallback program begins ...."<< endl<<endl; CAASysAlarm Alarm("House"); CAASysBurglar Burglar("Peter"); Burglar.Approach(&Alarm); Alarm.StartRinging(); cout << endl << "The CAASysCallback program is finished" << endl << endl; return(0); } |
Below is a listing of the traces produced by this program.
The CAASysCallback program begins .... Alarm House is created. Burglar Peter is alive. Burglar Peter approachs slowly House and opens his ears. Alarm House starts ringing. Burglar Peter run away House and very quickly. The CAASysCallback program is finished Burglar Peter is dead. Alarm House is deleted. |
[Top]
The callback mechanism enables publish/subscribe between objects. Any object can publish events, and any object can subscribe to events published by any other object. The publisher delegates to its callback manager the job of calling the subscribers on their requested methods, and the management of the subscriber list.
[Top]
[1] | The Callback Mechanism |
[2] | Building and Launching a CAA V5 Use Case |
[3] | Callback versus Send/Receive Mechanism |
[Top] |
Version: 1 [Jan 2000] | Document created |
Version: 2 [Fev 2004] | Document updated to enhance comments about the CATNotification class usage |
[Top] |
Copyright © 2000, Dassault Systèmes. All rights reserved.