3D PLM Enterprise Architecture

Middleware Abstraction - ENOVIA Event Model

Subscribing Automatically to Events

Working with events and subscribers
Use Case

Abstract

This article discusses the CAAVpiPackageSubscription use case. This use case explains how to subscribe automatically to events at the opening of the Login Session, via Session event listeners, taking the example of events fired by the File Manager object described in the CAAVpiPublishEvents use case.


What You Will Learn With This 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 CAAVpiAutomaticSubscription use case.

[Top]

The CAAVpiPackageSubscription Use Case

CAAVpiPackageSubscription is a use case of the CAAVPMInterfaces.edu framework that illustrates VPMInterfaces framework capabilities.

[Top]

What Does CAAVpiPackageSubscription Do

The CAAVpiPackageSubscription use case processes to a subscription at the opening of the Login Session through an object that listens to any Session events, 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 CAAVpiPackageSubscription use case is related to the CAAVpiEventObjects.m module where the following classes are defined:

[Top]

How to Launch CAAVpiPackageSubscription

To launch CAAVpiPackageSubscription, you will need to set up the build time environment, then to compile CAAVpiPackageSubscription 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:

[Top]

Where to Find the CAAVpiPackageSubscription Code

The CAAVpiPackageSubscription use case is made of a main named CAAVpiPackageSubscription.cpp located in the CAAVpiPackageSubscription.m module and two classes named CAAVpiFileManagerListener and CAAVpiSessionListener located in the CAAVpiEventObjects.m module of the CAAVPMInterfaces.edu framework.

Windows InstallRootDirectory\CAAVPMInterfaces.edu\CAAVpiPackageSubscription.m\(main)
InstallRootDirectory\CAAVPMInterfaces.edu\CAAVpiEventObjects.m\(listener classes)
Unix InstallRootDirectory/CAAVPMInterfaces.edu/CAAVpiPackageSubscription.m/(main)
InstallRootDirectory/CAAVPMInterfaces.edu/CAAVpiEventObjects.m/(listener classes)

where InstallRootDirectory is the directory where the CAA CD-ROM is installed.

[Top]

Step-by-Step

We can divide this use case in two distinct main parts:

  1. Implementation of the classes CAAVpiFileManagerListener and CAAVpiSessionListener
  2. Implementation of the main CAAVpiPackageSubscription.cpp

There are five steps in the first part of the CAAVpiPackageSubscription Use Case:

  1. Implement CAAIVpiFMEventCallbacks
  2. Get the current Login Session
  3. Get the Event Manager
  4. Create an instance of CAAVpiFileManagerListener class
  5. Subscribe to the events raised by instances of FileManager type

There are five main steps in the second part of the CAAVpiPackageSubscription Use Case:

  1. Create a Session
  2. Create a Login Session
  3. Create a publisher instance of class FileManager
  4. Raise some FileManager events
  5. Close the Sessions

We will now comment each of these sections in detail.

[Top]

Implement CAAIVpiFMEventCallbacks

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]

Get the current Login Session

After the implementation of the callback interface, we turn on now to the code responsible of the subscription.

In this use case, the automatic subscription is made through a Session event listener: CAAVpiSessionListener. To become a Session event listener, this class has to implement the ENOVISessionEvent interface.

However as the class is a data extension of the adapter class ENOVPackageListener, it has to overload a unique interesting method : onAfterCreateLoginSession.

Moreover, the late type of this extension is declared to be INFO_[package name]. Indeed, the underlying mechanism is the following: at the creation of the VPM Session, each package subscribes to the Login Session events (including CreateLoginSession) through its associated late type INFO_[package name]. Afterwards, as soon as the Login Session is created, each subscriber is called back in the method onAfterCreateLoginSession, where the code can carry out subscription on events of interest.

As we use the File Manager class as a publisher which is declared in the INDEX named package, we name our late type INFO_INDEX.

Here comes the sample code to do all this stuff:

...
// Object modeler declarations
CATImplementClass( CAAVpiSessionListener, DataExtension, ENOVPackageListener, INFO_INDEX );
#include "TIE_ENOVISessionEvent.h"
TIE_ENOVISessionEvent( CAAVpiSessionListener );

// onAfterCreateLoginSession implementation
HRESULT CAAVpiSessionListener::onAfterCreateLoginSession( const ENOVIEvent_var& iRaisedEvent, HRESULT& ioNotifyReturnCode )
{
	// code...
}
...

To finalize the implementation of the ENOVISessionEvent interface, we do not forget to complete the object modeler dictionary properly by adding the line:
INFO_INDEX ENOVISessionEvent libCAAVpiEventObjects
to the file CAAVPMInterfaces.edu.dic located in the directory CAAVPMInterfaces.edu/CNext/code/dictionary.

Be sure to uncomment this line before running this use case.

Then, the first step in the onAfterCreateLoginSession method is to retrieve the Login Session object as in the following code:

...
    //
    // ----------------------------
    // --> 1. Get the VPM Session
    // ----------------------------
    //
    VPMSession *pSession= VPMSession::OpenSession();
    if ( NULL == pSession ) 
    {
        cout << "Unable to Get the VPM Session" << endl;
        return E_FAIL;
    }
    cout << ">>package listener: Get VPM Session done " << endl;
    //
    CATIVpmLoginSession_var spLoginSession;
    HRESULT Rc = pSession->GetLoginSession( spLoginSession );
    if ( FAILED(Rc) || !spLoginSession )
    {
	cout<< "Unable to get the Login Session from the Session" << endl;
	return Rc;
    }
    cout << ">>package listener: Get Login Session done " << endl;
...

[Top]

Get the Event Manager

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 << ">>package 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]

Create an instance of CAAVpiFileManagerListener class

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. Package Subscriber creation
    // -----------------------------------
    //
    CAAVpiFileManagerListener* pCAAVpiFileManagerListener = new CAAVpiFileManagerListener( "Package Subscriber" );

    CAAIVpiFMEventCallBacks* piCAAIVpiFMEventCallBacks = NULL;
    Rc = pCAAVpiFileManagerListener->QueryInterface( IID_CAAIVpiFMEventCallBacks, (void**)& piCAAIVpiFMEventCallBacks );
    pCAAVpiFileManagerListener->Release();
    pCAAVpiFileManagerListener = NULL;
    if ( FAILED(Rc) )
    {
	cout<<"Unable to get a handler on Package Subscriber"<<endl;
	return Rc;
    }
    
    CATBaseUnknown_var spPackageSubscriber = piCAAIVpiFMEventCallBacks;
    piCAAIVpiFMEventCallBacks->Release();
    piCAAIVpiFMEventCallBacks = NULL;
    if ( NULL_var == spPackageSubscriber )
    {
	cout<<"Unable to get a handler on Package Subscriber"<<endl;
        return Rc;
    }
    cout << ">>package listener: Get a CAAIVpiFMEventCallBacks handler on Package Subscriber done " << endl;

...

[Top]

Subscribe to the events raised by instances of FileManager type

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, spPackageSubscriber, IID_CAAIVpiFMEventCallBacks, &cookie, ENOVIEvent::EventFireBefore );
    if ( FAILED(Rc) )
    {
	cout<<"Unable to subscribe on CreateFile"<<endl;
	return Rc;
    }
    cout << ">>package listener: Subscribe on CreateFile (before) done " << endl;

    Rc = spEventManager->Subscribe( EventName, EventPublisherType, spPackageSubscriber, IID_CAAIVpiFMEventCallBacks, &cookie, ENOVIEvent::EventFireAfter );
    if ( FAILED(Rc) )
    {
	cout<<"Unable to subscribe on CreateFile"<<endl;
	return Rc;
    }
    cout << ">>package listener: Subscribe on CreateFile (after) done " << endl;
    //
    // Etc. Idem for Move and Delete File events
...

[Top]

Create a Session

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]

Create a Login Session

Then we have to create the Login Session. During its creation the Session event listener will be called and some subscriptions will be made.

The interest of this step is hence to see the traces at execution time: you should see the Session listener being called back after the creation of the Login Session and doing the subscriptions.

...
    //
    // -------------------------------
    // --> 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]

Create a publisher instance of class FileManager

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]

Raise some FileManager events

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]

Close the Sessions

Each opened session must be closed as followed:

...
    // --------------------------------------------
    // --> 5. 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 CAAVpiPackageSubscription use case.

[Top]

In Short

This use case has demonstrated one way to automatically subscribe to events via the extension of the ENOVPackageListener class and how to be called back when they are raised.

[Top]


References

[1] Building and Launching a CAA V5 Use Case
[2] The ENOVIA Event Model
[Top]

History

Version: 2 [Oct 2003] Document updated
Version: 1 [Oct 2001] Document created
[Top]

Copyright © 2003, Dassault Systèmes. All rights reserved