3D PLM Enterprise Architecture |
Middleware Abstraction - ENOVIA Event Model |
Subscribing Automatically to EventsWorking with events and subscribers |
Use Case |
AbstractThis article discusses the CAAVpiAutomaticSubscription use case. This use case explains how to subscribe automatically to events at the opening of the Login Session, via the ENOVIEventPlugin interface, taking the example of events fired by the File Manager object described in the CAAVpiPublishEvents use case. |
This use case is intended to show you one of the two ways that can be used to automatically subscribe to events and how to implement the dedicated callback interfaces to handle these events when they are raised. The second way is illustrated in the CAAVpiPackageSubscription use case.
[Top]
CAAVpiAutomaticSubscription is a use case of the CAAVPMInterfaces.edu framework that illustrates VPMInterfaces framework capabilities.
[Top]
The CAAVpiAutomaticSubscription use case processes to a subscription at the opening of the Login Session through a dedicated plug-in functionality, then raises the events that have been subscribed to, and finally calls the corresponding subscribers back. The events that are subscribed to in this sample are fired by the File Manager object of the CAAVpiPublishEvents use case.
The CAAVpiAutomaticSubscription use case is related to the CAAVpiEventObjects.m module where the following classes are defined:
[Top]
To launch CAAVpiAutomaticSubscription, you will need to set up the build time environment, then to compile CAAVpiAutomaticSubscription along with its prerequisites, to set up the run time environment, and then to execute the use case [1].
Launch the use case as follows:
e:>CAAVpiAutomaticSubscription |
$ CAAVpiAutomaticSubscription |
[Top]
The CAAVpiAutomaticSubscription use case is made of a main named CAAVpiAutomaticSubscription.cpp located in the CAAVpiAutomaticSubscription.m module and three classes named CAAVpiFileManagerListener, CAAVpiPlugin, and CAAVpiPluginListener located in the CAAVpiEventObjects.m module of the CAAVPMInterfaces.edu framework.
Windows | InstallRootDirectory\CAAVPMInterfaces.edu\CAAVpiAutomaticSubscription.m\(main) InstallRootDirectory\CAAVPMInterfaces.edu\CAAVpiEventObjects.m\(plugin+listeners classes) |
Unix | InstallRootDirectory/CAAVPMInterfaces.edu/CAAVpiAutomaticSubscription.m/(main) InstallRootDirectory/CAAVPMInterfaces.edu/CAAVpiEventObjects.m/(plugin+listeners classes) |
where InstallRootDirectory is the directory where the CAA CD-ROM is installed.
[Top]
We can divide this use case in two distinct main parts:
There are seven steps in the first part of the CAAVpiAutomaticSubscription Use Case:
There are five main steps in the second part of the CAAVpiAutomaticSubscription Use Case:
We will now comment each of these sections in detail.
[Top]
The CAAVpiFileManagerListener class is an early subscriber that implements the specific callback interface provided by the publisher of the events of interest. For this use case, we are interested in the events emitted by the FileManager. Hence the early Subscriber will implement the CAAIVpiFMEventCallbacks interface.
Our implementation of this interface follows the CAA Object Modeler rules applied to all interface implementations.
Here is a sample of the important steps.
... // Object modeler declarations CATImplementClass( CAAVpiFileManagerListener, Implementation, CATBaseUnknown, CATNull ); #include "TIE_CAAIVpiFMEventCallBacks.h" TIE_CAAIVpiFMEventCallBacks( CAAVpiFileManagerListener ); // Actual implementation HRESULT CAAVpiFileManagerListener::onKo( const ENOVIEvent_var& iRaisedEvent, HRESULT& ioNotifyReturnCode ) { //code... } HRESULT CAAVpiFileManagerListener::onBeforeCAACreateFile( const ENOVIEvent_var& iRaisedEvent, HRESULT& ioNotifyReturnCode ) { //code... } HRESULT CAAVpiFileManagerListener::onAfterCAACreateFile( const ENOVIEvent_var& iRaisedEvent, HRESULT& ioNotifyReturnCode ) { //code... } // Idem for Move and Delete File events... ... |
To finalize the implementation of the callback interface, we do not forget to
complete the object modeler dictionary properly by adding the line:
CAAVpiFileManagerListener CAAIVpiFMEventCallBacks libCAAVpiEventObjects
to the file CAAVPMInterfaces.edu.dic located in the directory
CAAVPMInterfaces.edu/CNext/code/dictionary.
[Top]
In this use case, the automatic subscription is made through a plug-in functionality. To turn this functionality on, the class CAAVpiPlugin will implement the ENOVIEventPlugin interface which declares a unique method : Init.
The whole mechanism is as follows:
Notes:
Now comes the sample code that implements ENOVIEventPlugin according to this rules:
... // Object modeler declarations CATImplementClass( CAAVpiPlugin, DataExtension, CATBaseUnknown, T_CAAVpiPlugin ); #include "TIE_ENOVIEventPlugin.h" TIE_ENOVIEventPlugin( CAAVpiPlugin ); // Init implementation HRESULT CAAVpiPlugin::Init( const ENOVIEventManager_var &spEventManager ) { // (see source file for details...) // --> 1. Create an instance of CAAVpiPluginListener // --> 2. Check that the listener implements ENOVISessionEvent interface // --> 3. Retrieve a smart pointer on type CATBaseUnknown, required by the Subscribe method // --> 4. Subscribe to the event CreateLoginSession step After (early mode, on type) } ... |
To finalize the implementation of the ENOVIEventPlugin interface, we do not forget to complete the object modeler dictionary properly by adding the line:
T_CAAVpiPlugin ENOVIEventPlugin libCAAVpiEventObjects
to the file CAAVPMInterfaces.edu.dic located in the directory CAAVPMInterfaces.edu/CNext/code/dictionary
[Top]
After the implementation of the ENOVIEventPlugin interface, we turn on to the code responsible of the subscriptions of interest.
This is done in the class CAAVpiPluginListener, that derives of the adapter class ENOVPackageListener and implements ENOVISessionEvent, in the callback method onAfterCreateLoginSession.
The first step in the onAfterCreateLoginSession method is to retrieve the VPM Login Session object as in the following code:
... // Object modeler declarations CATImplementClass( CAAVpiPluginListener, Implementation, CATBaseUnknown, CATNull ); #include "TIE_ENOVISessionEvent.h" TIE_ENOVISessionEvent( CAAVpiPluginListener ); HRESULT CAAVpiPluginListener::onAfterCreateLoginSession( const ENOVIEvent_var& iRaisedEvent, HRESULT& ioNotifyReturnCode ) { HRESULT Rc = S_OK; // // ---------------------------- // --> 1. Get the VPM Session // ---------------------------- // VPMSession *pSession= VPMSession::OpenSession(); if ( NULL == pSession ) { cout << "Unable to Get the VPM Session" << endl; return E_FAIL; } cout << ">>plugin listener: Get VPM Session done " << endl; // // ------------------------------ // --> 1bis. Get the Login Session // ------------------------------ // CATIVpmLoginSession_var spLoginSession; Rc = pSession->GetLoginSession( spLoginSession ); if ( FAILED(Rc) || !spLoginSession ) { cout << "Unable to get the Login Session from the Session" << endl; return Rc; } cout << ">>plugin listener: Get Login Session done " << endl; ... |
To finalize the implementation of the ENOVISessionEvent interface, we do not forget to complete the object modeler dictionary properly by adding the line:
CAAVpiPluginListener ENOVISessionEvent libCAAVpiEventObjects
to the file CAAVPMInterfaces.edu.dic located in the directory CAAVPMInterfaces.edu/CNext/code/dictionary
[Top]
Here is the code to do it.
... // // ------------------------------ // --> 2. Get the Event Manager // ------------------------------ // ENOVIEventManager_var spEventManager; Rc = spLoginSession->get_ENOVEventManager( spEventManager ); if ( FAILED(Rc) ) { cout<<"Unable to get the Event Manager from the Session"<<endl; return Rc; } cout << ">>plugin listener: Get Event Manager done " << endl; ... |
The Event Manager is used to subscribe to events on object types or instances. By implementing appropriate callback interfaces declared by the ENOVIA domains (referred to as early subscribing) or a generic callback interface named ENOVISubscriberEvent (referred to as late subscribing), clients can do some actions when events are raised by a given type or a given instance of object.
[Top]
In this step as soon as the subscriber is created, a query interface is carried out to retrieve the appropriate smart pointers the Subscribe method is waiting for.
... // // ----------------------------------- // --> 3. Plugin Subscriber creation // ----------------------------------- // CAAVpiFileManagerListener* pCAAVpiFileManagerListener = new CAAVpiFileManagerListener( "FileManager Subscriber" ); CAAIVpiFMEventCallBacks* piCAAIVpiFMEventCallBacks = NULL; Rc = pCAAVpiFileManagerListener->QueryInterface( IID_CAAIVpiFMEventCallBacks, (void**)& piCAAIVpiFMEventCallBacks ); pCAAVpiFileManagerListener->Release(); pCAAVpiFileManagerListener = NULL; if ( FAILED(Rc) ) { cout<<"Unable to get a CAAIVpiFMEventCallBacks handler on FileManager Subscriber"<<endl; return Rc; } CATBaseUnknown_var spPluginSubscriber = piCAAIVpiFMEventCallBacks; piCAAIVpiFMEventCallBacks->Release(); piCAAIVpiFMEventCallBacks = NULL; if ( NULL_var == spPluginSubscriber ) { cout<<"Unable to get a CATBaseUnknown handler on FileManager Subscriber"<<endl; return Rc; } ... |
[Top]
This step is the subscription itself thanks to the Event Manager. It is referred to as a type subscription as the argument for the publisher is the string representing its type i.e. FileManager here.
... // // ---------------------------------------- // --> 4. Subscribe on Create File // (EARLY MODE Subscription on TYPE) // ---------------------------------------- // CATUnicodeString EventName ( "CAACreateFile" ); CATUnicodeString EventPublisherType ( "CAAVpiFileManager" ); unsigned long cookie = 0; Rc = spEventManager->Subscribe( EventName, EventPublisherType, spPluginSubscriber, IID_CAAIVpiFMEventCallBacks, &cookie, ENOVIEvent::EventFireBefore ); if ( FAILED(Rc) ) { cout<<"Unable to subscribe on CreateFile"<<endl; return Rc; } cout << ">>plugin listener: Subscribe on CreateFile (before) done " << endl; Rc = spEventManager->Subscribe( EventName, EventPublisherType, spPluginSubscriber, IID_CAAIVpiFMEventCallBacks, &cookie, ENOVIEvent::EventFireAfter ); if ( FAILED(Rc) ) { cout<<"Unable to subscribe on CreateFile"<<endl; return Rc; } cout << ">>plugin listener: Subscribe on CreateFile (after) done " << endl; // // Etc. Idem for Move and Delete File events ... |
[Top]
Finally the last step of this first part is to declare our plug-in implementation through the creation of a resource file. To do this, in the directory CAAVPMInterfaces.edu/CNext/resources/msgcatalog, a file named CAAVpiPluginList.CATRsc has been created and just contains the line:
T_CAAVpiPlugin = "0";
which simply states that the late type
However, at runtime, a new step is also required to declare the resource file name to be looked for, i.e.
export VPM_PLUGIN_OBJECTS_LIST=CAAVpiPluginList
This completes the first part of the CAAVpiAutomaticSubscription use case.
[Top]
Now begins the second part of this use case, which describes the main
program.
The first thing to do in any Enovia program is to create the VPM Session. Here
is the code to do it:
... // // --------------------------- // --> 1. Open a VPM Session // --------------------------- // cout << "main: Open VPM Session ... " << endl; VPMSession* pSession = VPMSession::OpenSession(); if ( NULL == pSession ) { cout << "Unable to Open a VPM Session" << endl; return 1; } cout << "main: Open VPM Session done " << endl << endl; ... |
[Top]
Then we have to create the Login Session. During its creation the plug-in
implementation will be called and just after its creation our subscriptions will
be made.
The interest of this step is hence to see the traces at execution time: you
should see the plug-in implementation being called, subscribing to event
CreateLoginSession step After, and then the listener being called back and doing
the subscriptions to the File Manager events.
... // // ------------------------------- // --> 2. Login Session creation // ------------------------------- // cout << "main: Create LoginSession ... " << endl; const int NetWorkCommunication = 0; CATIVpmLoginSession_var spLoginSession; Rc = pSession->CreateLoginSession( "MyUserID", "MyPassword", "MyRoleName", NetWorkCommunication, spLoginSession ); if ( FAILED(Rc) ) { cout<<"Unable to Create Login Session"<<endl; return 2; } cout << "main: Create LoginSession done " << endl << endl; ... |
[Top]
To fire the events we have subscribed to, we need an instance of the CAAVpiFileManager class.
Here is the corresponding code:
... // // ------------------------------- // --> 3. File Manager creation // ------------------------------- // cout << "main: Create File Manager ... " << endl; CAAVpiFileManager* pFileManager = new CAAVpiFileManager( "File Manager" ); if ( NULL == pFileManager ) { cout<<"Unable to Create File Manager"<<endl; return 3; } cout << "main: Create File Manager done " << endl << endl; ... |
[Top]
Now we are ready to fire Create, Move and Delete File events and to look at the traces to see if our subscriber is actually called back.
... // // --------------------------------------- // --> 4. Fire Create, Move, Delete File // --------------------------------------- // CATUnicodeString FileName ( "CAAVpiUseCase.h" ); CATUnicodeString FirstDirectory ( "PublicInterfaces" ); Rc = pFileManager->CAACreateFile( FileName, FirstDirectory ); if ( FAILED(Rc) ) { cout<<"Unable to Create File"<<endl; return 4; } cout << "main: Create File done " << endl << endl; // // Etc. Same code for Move and Delete File... ... |
[Top]
Each opened session must be closed as followed:
... // -------------------------------------------- // --> 7. Close Login Session and VPM Session // -------------------------------------------- // Rc = spLoginSession->Close(); if ( FAILED(Rc) ) { cout<<"Unable to Close Login Session"<<endl; return 7; } cout << "main: Close Login Session done " << endl; VPMSession::CloseSession(); cout << "main: Close VPM Session done " << endl; ... |
This step concludes the second part of the CAAVpiAutomaticSubscription use case.
[Top]
This use case has demonstrated one way to automatically subscribe to events via the ENOVIEventPlugin interface and how to be called back when they are raised.
[Top]
[1] | Building and Launching a CAA V5 Use Case |
[2] | The ENOVIA Event Model |
[Top] |
Version: 2 [Oct 2003] | Document updated for new interface ENOVIEventPlugin |
Version: 1 [Oct 2001] | Document created |
[Top] |
Copyright © 2003, Dassault Systèmes. All rights reserved.