3D PLM Enterprise Architecture

Middleware Abstraction - ENOVIA Event Model

Subscribing Automatically to Login Session Events

Working with events and subscribers
Use Case

Abstract

This article discusses the CAAVpiAutomaticSubscription2 use case, which is a particular case of the CAAVpiAutomaticSubscription use case. Indeed, this use case explains how to subscribe automatically to events raised by the Login Session itself, via the ENOVIEventPlugin interface. Note that those events cannot be subscribed to in the method Init of the plug-in, since the Login Session object is not accessible at that time. Only a subscription to event CreateLoginSession step After is allowed there. The main purpose of this use case is hence to show how you can do it.


What You Will Learn With This Use Case

This use case is intended to show you the recommanded method to be used to automatically subscribe to the events raised by the Login Session itself. It also shows how to implement the dedicated callback interfaces to handle these events when they are raised.

[Top]

The CAAVpiAutomaticSubscription2 Use Case

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

[Top]

What Does CAAVpiAutomaticSubscription2 Do

The CAAVpiAutomaticSubscription2 use case processes to a subscription at the opening of the Login Session through the dedicated plug-in functionality illustrated by the CAAVpiAutomaticSubscription use case. The subscription is done on the step After of the event CreateLoginSession. Then in the associated callback interface, a second subscription is done on the steps Before and After of the event SaveLoginSession. Finally, the main program raises the event that has been subscribed to and the corresponding subscriber is called back.

The CAAVpiAutomaticSubscription2 use case is related to the CAAVpiEventObjects.m module where the following classes are defined:

[Top]

How to Launch CAAVpiAutomaticSubscription2

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

The CAAVpiAutomaticSubscription2 use case is made of a main named CAAVpiAutomaticSubscription2.cpp located in the CAAVpiAutomaticSubscription2.m module and two classes named CAAVpiListenAndSubscribe and CAAVpiPlugin4Subscribing2Session located in the CAAVpiEventObjects.m module of the CAAVPMInterfaces.edu framework.

Windows InstallRootDirectory\CAAVPMInterfaces.edu\CAAVpiAutomaticSubscription2.m\(main)
InstallRootDirectory\CAAVPMInterfaces.edu\CAAVpiEventObjects.m\(plugin+listener class)
Unix InstallRootDirectory/CAAVPMInterfaces.edu/CAAVpiAutomaticSubscription2.m/(main)
InstallRootDirectory/CAAVPMInterfaces.edu/CAAVpiEventObjects.m/(plugin+listener class)

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

[Top]

Step-by-Step

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

  1. Implementation of ENOVIEventPlugin in the class CAAVpiPlugin4Subscribing2Session
  2. Implementation of ENOVISessionEvent in the class CAAVpiListenAndSubscribe
  3. Implementation of the main CAAVpiAutomaticSubscription2.cpp

There are three main steps in the first part of the CAAVpiAutomaticSubscription2 Use Case: Implementation of ENOVIEventPlugin

  1. Create an instance of the class CAAVpiListenAndSubscribe
  2. Subscribe to the step After of the event CreateLoginSession
  3. Create a resource file to declare this plug-in

There are two main steps in the second part of the CAAVpiAutomaticSubscription2 Use Case: Implementation of ENOVISessionEvent

  1. Subscribe to the event SaveLoginSession in method onAfterCreateLoginSession
  2. Implement onBefore- and onAfterSaveLoginSession methods

There are four main steps in the third part of the CAAVpiAutomaticSubscription2 Use Case:

  1. Create a Session
  2. Create a Login Session
  3. Save the Login Session
  4. Close the Sessions

We will now comment each of these sections in detail.

[Top]

Create an instance of the class CAAVpiListenAndSubscribe

In this use case, the automatic subscription is made through a plug-in functionality. To use this functionality the class CAAVpiPlugin4Subscribing2Session has to implement the ENOVIEventPlugin interface which declares a unique method : Init. Then, during the creation of the Login Session, each implementation of the ENOVIEventPlugin interface is called on the method Init where the code can carry out the subscription on event CreateLoginSession step After only.

We first do some object modeler declarations:

...
// Object modeler declarations
CATImplementClass( CAAVpiPlugin4Subscribing2Session, 
                   DataExtension, 
                   CATBaseUnknown, 
                   T_CAAVpiPlugin4Subscribing2Session );
#include "TIE_ENOVIEventPlugin.h"
TIE_ENOVIEventPlugin( CAAVpiPlugin4Subscribing2Session );

// Init implementation
HRESULT CAAVpiPlugin4Subscribing2Session::Init( const ENOVIEventManager_var &spEventManager )
{
	// code...
}
...

To finalize the implementation of the plug-in interface, we do not forget to complete the object modeler dictionary properly by adding the line:

T_CAAVpiPlugin4Subscribing2Session ENOVIEventPlugin libCAAVpiEventObjects

to the file CAAVPMInterfaces.edu.dic located in the directory CAAVPMInterfaces.edu/CNext/code/dictionary

Then, the first step in the Init method is to create an instance of the subscriber. 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.

...
    //
    // -----------------------------------
    // --> 1. Plugin Subscriber creation
    // -----------------------------------
    //
    CAAVpiListenAndSubscribe* pCAAVpiListenAndSubscribe = new CAAVpiListenAndSubscribe();
    //
    ENOVISessionEvent* piENOVISessionEvent = NULL;
    Rc = pCAAVpiListenAndSubscribe->QueryInterface( IID_ENOVISessionEvent, (void**)& piENOVISessionEvent );
    pCAAVpiListenAndSubscribe->Release();
    pCAAVpiListenAndSubscribe = NULL;
    if ( FAILED(Rc) )
    {
	cout<<"Unable to get a handler on Plugin Subscriber"<<endl;
	return Rc;
    }
    cout << ">>plugin: Get a ENOVISessionEvent handler on Plugin Subscriber done " << endl;
    //
    CATBaseUnknown_var spPluginSubscriber = piENOVISessionEvent;
    piENOVISessionEvent->Release();
    piENOVISessionEvent = NULL;
    if ( NULL_var == spPluginSubscriber )
    {
	cout<<"Unable to get a handler on Plugin Subscriber"<<endl;
        return E_FAIL;
    }
    cout << ">>plugin: Get a CATBaseUnknown handler on Plugin Subscriber done " << endl;

...

[Top]

Subscribe to the step After of the event CreateLoginSession

This step is the subscription itself thanks to the Event Manager. It is referred to as a type subscription since the argument for the publisher is the string VPMSession itself.

...
    //
    // ----------------------------------------
    // --> 4. Subscribe on After Create Login Session event
    //         EARLY MODE Subscription on type VPMSession
    // ----------------------------------------
    //
    CATUnicodeString EventName ( "CreateLoginSession" );
    CATUnicodeString EventPublisherType ( "VPMSession" );
    unsigned long cookie = 0;
    Rc = spEventManager->Subscribe( EventName, 
                                       EventPublisherType, 
                                       spPluginSubscriber, 
                                       IID_ENOVISessionEvent, 
                                       &cookie, 
                                       ENOVIEvent::EventFireAfter );
    if ( FAILED(Rc) )
    {
	cout<<"Unable to subscribe on CreateLoginSession"<<endl;
	return Rc;
    }
    cout << ">>plugin: Subscribe on CreateLoginSession (after) done " << endl;

...

[Top]

Create a resource file to declare the plug-in

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 CAAVpiPluginList2.CATRsc has been created and just contains the line:

T_CAAVpiPlugin4Subscribing2Session = "0";

which simply states that the late type T_CAAVpiPlugin4Subscribing2Session implements the ENOVIEventPlugin interface and has to be called during the Login Session creation.

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=CAAVpiPluginList2

This completes the first part of the CAAVpiAutomaticSubscription2 use case.

[Top]

Subscribe to the event SaveLoginSession in method onAfterCreateLoginSession

Now begins the second part of this use case in which we will implement ENOVISessionEvent.

The CAAVpiListenAndSubscribe class is an early subscriber that implements the callback interface ENOVISessionEvent since we are interested in Login Session events.

We hence begin with object modeler declarations.

...
// Object modeler declarations
CATImplementClass( CAAVpiListenAndSubscribe, Implementation, CATBaseUnknown, CATNull );
#include "TIE_ENOVISessionEvent.h"
TIE_ENOVISessionEvent( CAAVpiListenAndSubscribe );
...

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

We can now implement the ENOVISessionEvent methods and first of all the method onAfterCreateLoginSession. We will be called back here at the end of the Login Session creation since we subscribed to this event via the plug-in. In this method we can subscribe to the event SaveLoginSession since the Login Session is now fully available.

The subscription looks like the subscription shown in the first step above. However we have first to get the VPMSession, then the Login Session, and finally the Event Manager to do the subscription. Note that the subscriber instance is the instance of CAAVpiListenAndSubscribe itself (i.e. this).

...
    ENOVISessionEvent* piENOVISessionEvent = NULL;
    Rc = QueryInterface( IID_ENOVISessionEvent, (void**)& piENOVISessionEvent );
    if ( FAILED(Rc) )
    {
	cout<<"Unable to get a handler on Plugin Subscriber"<<endl;
	return Rc;
    }
    cout<<">>plugin listener: Get a ENOVISessionEvent handler on Plugin Subscriber done"<<endl;
    //    
    CATBaseUnknown_var spPluginSubscriber = piENOVISessionEvent;
    piENOVISessionEvent->Release();
    piENOVISessionEvent = NULL;
    if ( NULL_var == spPluginSubscriber )
    {
	cout<<"Unable to get a handler on Plugin Subscriber"<<endl;
        return E_FAIL;
    }
    cout<<">>plugin listener: Get a CATBaseUnknown handler on Plugin Subscriber done"<<endl;
    //
    // ----------------------------------------
    // --> 4. Subscribe on Save login Session event (before & after)
    //         EARLY MODE Subscription on instance of LoginSession
    // ----------------------------------------
    //
    CATUnicodeString EventName ( "SaveLoginSession" );
    CATIVpmLoginSession_var oLoginSession = NULL_var;
    pSession->GetLoginSession( oLoginSession );
    ENOVIPublisher_var spSessionPublisher = oLoginSession;
    unsigned long cookie = 0;
    Rc = spEventManager->Subscribe( EventName, 
                                       spSessionPublisher, 
                                       spPluginSubscriber, 
                                       IID_ENOVISessionEvent, 
                                       &cookie, 
                                       ENOVIEvent::EventFireBefore );
    if ( FAILED(Rc) )
    {
	cout<<"Unable to subscribe on Save login Session"<<endl;
	return Rc;
    }
    cout << ">>plugin listener: Subscribe on Save login Session (before) done " << endl;

    // Etc. Idem for step after
...

[Top]

Implement onBefore- and onAfterSaveLoginSession methods

Finally we can implement the two methods related to the Save Login Session event in which we will be called back thanks to the above subscription. For example, a sample code will look like the following.

...
HRESULT CAAVpiListenAndSubscribe::onBeforeSaveLoginSession(const ENOVIEvent_var& iRaisedEvent, 
                                                           HRESULT& ioNotifyReturnCode)
{
    HRESULT Rc = S_OK;

    CATUnicodeString iEventName;
    Rc = iRaisedEvent->GetName( iEventName );
    if( SUCCEEDED(Rc) )
    // etc.
        
    ioNotifyReturnCode = S_OK;
    return Rc ;    
}
...

Note that not all the methods of ENOVISessionEvent have to be implemented since the class CAAVpiListenAndSusbcribe derives from the adapter class ENOVPackageListener as recommended.

[Top]

Create a Session

Now begins the third and last 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 plug-in will be called and the subscription to event CreateLoginSession step After will be made.
The interest of this step is also to see the traces at execution time: you should see the 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;
        VPMSession::CloseSession();
        return 2;
    }
    cout << "main: Create LoginSession done " << endl << endl;
...

[Top]

Save the Login Session

Now we are ready to fire SaveLoginSession event and to look at the traces to see if our subscriber is actually called back.

...
    //
    // ---------------------------------------
    // --> 3. Fire Save Login Session
    // ---------------------------------------
    //
    cout << "main: Save Login Session ... " << endl;	
    Rc = spLoginSession->Save();
    if ( FAILED(Rc) )
    {
	cout<<"Unable to Save Login Session"<<endl;
        VPMSession::CloseSession();
	return 3;
    }
    cout << "main: Save Login Session done " << endl << endl;
...

[Top]

Close the Sessions

Each opened session must be closed as followed:

...
    // --------------------------------------------
    // --> 4. Close Login Session and VPM Session
    // --------------------------------------------
    //
    Rc = spLoginSession->Close();
    if ( FAILED(Rc) )
    {
	cout<<"Unable to Close Login Session"<<endl;
	return 4;
    }
    cout << "main: Close Login Session done " << endl;

    VPMSession::CloseSession();
    cout << "main: Close VPM Session done " << endl;
...

This step concludes the third part of the CAAVpiAutomaticSubscription2 use case.

[Top]

In Short

This use case has demonstrated the way to automatically subscribe to Login Session events via the ENOVIEventPlugin interface 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 for new interface ENOVIEventPlugin
Version: 1 [Mar 2003] Document created
[Top]

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