3D PLM Enterprise Architecture

Middleware Abstraction - Object Modeler

Creating and Instantiating a Component

Implementing CATICreateInstance and using CATInstantiateComponent
Use Case

Abstract

This article shows how to create and instantiate a CAA V5 component.


What You Will Learn With This Use Case

This use case is intended to show you how to create a CAA V5 component that isolates you implementation from client applications and how client application can instantiate it. The component represents an object with two facets, each of them being supported using an interface:

  1. The first facet is described in ths article. It is the ability for the component to be instantiated by client applications thanks to implementing the CATICreateInstance interface and its single method CreateInstance in a code extension. Client application instantiate the component using the CATInstantiateComponent global function.
  2. The second facet is the ability to print a message on the screen thanks to an interface created for the use case and named CAAISysMyInterface. You could easily find other facets in the industrial domains you deal with to create a more realistic component that implements a lot more interfaces. creating this interface and its implementation is not described. You can refer to other articles dealing with this topic [1] [2].

[Top]

The CAASysComponent Use Case

CAASysComponent is a use case of the CAASystem.edu framework that illustrates the System framework capabilities.

[Top]

What Does CAASysComponent Do

This use case shows a template of the code to write to create a basic component and to enable client applications to instantiate it, retrieve a pointer to an interface this component implements, use this pointer to call methods, and navigate among the other possible interfaces the component implements.

This component is made of the CAASysComponent main class, and of the CAAESysCreateInstanceForComponent extension class. CAAESysCreateInstanceForComponent implements the CATICreateInstance interface to enable the component creation. It is also made of the CAAESysMyInterfaceForComponent class that implements the CAAISysMyInterface interface. Other interfaces could be implemented to replace the latter and make a more realistic component, but have uselessly complicated the use case.

A main program instantiates the component and retrieves a pointer to this CAAISysMyInterface interface to show what the client should do.

Note: Extension links are shown as dashed arrows. Other links are shown as usual.

[Top]

How to Launch CAASysComponent

You first need to build CAASysComponent. To do this, you will need to set up the build time environment, then compile the four CAASysComponent*.m modules along with their prerequisites as described in [5]. Launch CAASysComponentCreate itself.

[Top]

Where to Find the CAASysComponent Code

The CAASysComponent.m use case is made of four modules:

Windows InstallRootDirectory\CAASystem.edu\CAASysComponent*.m
Unix InstallRootDirectory/CAASystem.edu/CAASysComponent*.m

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

These modules are:

  1. CAASysComponentImpl.m that contains the component main class and the extension class that implements CATICreateInstance
  2. CAASysComponentCreate.m that contains the main program that instantiates the component
  3. CAASysComponentInt.m that contains the CAAISysMyInterface  interface and its TIE, the interface header being located in the PublicInterfaces directory of the CAASystem.edu framework
  4. CAASysComponentExt that contains the extension class that implements CAAISysMyInterface

The first two modules are described in this article. The two others are not described. Refer to their source code. 

[Top]

Step-by-Step

To create a component such as CAASysComponent, there are nine main steps:

# Step Where
1 Create the CAASysComponent component main class header file CAASysComponent.m\LocalInterfaces\CAASysComponent.h
2 Create the CAASysComponent component main class source file CAASysComponent.m\src\CAASysComponent.cpp
3 Create the CAAESysCreateInstanceForComponent extension class header file CAASysComponent.m\LocaInterfaces\CAAESysCreateInstanceForComponent.h
4 Create the CAAESysCreateInstanceForComponent extension class source file CAASysComponent.m\src\CAAESysCreateInstanceForComponent.cpp
5 Update the interface dictionary CAASystem.edu.dico file in CNext\code\dictionary
6 Instantiate and use the component CAASysComponent.m\src\CAASysMain.cpp

[Top]

Creating the CAASysComponent Header File

#include "CATBaseUnknown.h"   //Needed to derive from CATBaseUnknown

class  CAASysComponent : public CATBaseUnknown
{
  // Used in conjunction with CATImplementClass in the .cpp file
  CATDeclareClass;

  public:

    CAASysComponent();
    virtual ~CAASysComponent();

  private:

    // Copy constructor, not implemented
    // Set as private to prevent from compiler automatic creation as public.
    CAASysComponent(const CAASysComponent &iObjectToCopy);

    // Assignment operator, not implemented
    // Set as private to prevent from compiler automatic creation as public.
    CAASysComponent & operator = (const CAASysComponent &iObjectToCopy);

};

The CAASysComponent class C++-derives from CATBaseUnknown. The CATDeclareClass macro declares that the class CAASysComponent belongs to a component. Note that the copy constructor is set as private. The class has a constructor and a destructor only.

[Top]

Creating the CAASysComponent Source File

#include "CAASysComponent.h"

//C++ standard library
#include "iostream.h"

//------------------------------------------------------------------------------------

// To declare that the class is a component main class 
CATImplementClass(CAASysComponent, Implementation, CATBaseUnknown, CATNull);

//------------------------------------------------------------------------------------

CAASysComponent::CAASysComponent() 
{
  cout << "CAASysComponent::CAASysComponent" << endl;
}

CAASysComponent::~CAASysComponent()
{
  cout << "CAASysComponent::~CAASysComponent" << endl;
}

The CATImplementClass macro declares that the CAASysComponent class is a component main class thanks the Implementation keyword, and OM-derives [6] from CATBaseUnknown. Any component main class declared as an Implementation must C++-derive and OM-derive from the same class, that must either be CATBaseUnknown or another component main class. The component main class doesn't implement any interface, but it could.

[Top]

Creating the CAAESysCreateInstanceForComponent Extension Class Header File

#include "CATBaseUnknown.h"   //Needed to derive from CATBaseUnknown

class CAAESysCreateInstanceForComponent : public CATBaseUnknown
{
  // Used in conjunction with CATImplementClass in the .cpp file
  CATDeclareClass;

  public:

    CAAESysCreateInstanceForComponent();
    virtual ~CAAESysCreateInstanceForComponent();

    // CATICreateInstance 
    // -------------------

    virtual HRESULT __stdcall CreateInstance(void **oppv);

  private:

    // Copy constructor, not implemented
    // Set as private to prevent from compiler automatic creation as public.
    CAAESysCreateInstanceForComponent(const CAAESysCreateInstanceForComponent &iObjectToCopy);

    // Assignment operator, not implemented
    // Set as private to prevent from compiler automatic creation as public.
    CAAESysCreateInstanceForComponent & operator = (const CAAESysCreateInstanceForComponent &iObjectToCopy);

};

The CAAESysCreateInstanceForComponent extension class derives from CATBaseUnknown. The CATDeclareClass macro declares that the class CAAESysCreateInstanceForComponent belongs to a component. The class has a constructor and a destructor, and declares the CreateInstance method which is the only method of the CATICreateInstance interface. Note that the copy constructor and the assignment operator are set as private. This is very important for extensions. Since extensions must never be directly instantiated by client applications, this prevents the compiler from creating the copy constructor and the assignment operator as public without you know. They are not implemented in the source file.

[Top]

Creating the CAAESysComponent Extension Class Source File

//Local Framework
#include "CAAESysCreateInstanceForComponent.h"

//C++ standard library
#include "iostream.h"

// The class to create
#include "CAASysComponent.h"

// System Framework
#include <CATErrorDef.h>

//-----------------------------------------------------------------------------------
// To create the TIE object
#include "TIE_CATICreateInstance.h"
TIE_CATICreateInstance(CAAESysCreateInstanceForComponent);

// To declare that the class is a Code extension of CAASysComponent
//
CATImplementClass(CAAESysCreateInstanceForComponent, CodeExtension, CATBaseUnknown, CAASysComponent);
// 
// To declare that CAAESysCreateInstanceForComponent implements CATICreateInstance, insert 
// the following line in the interface dictionary:
//
//    CAASysComponent CATICreateInstance  libCAASysComponentImpl
//
//------------------------------------------------------------------------------------

CAAESysCreateInstanceForComponent::CAAESysCreateInstanceForComponent() 
{
  cout << "CAAESysCreateInstanceForComponent::CAAESysCreateInstanceForComponent" << endl;
}

//------------------------------------------------------------------------------------

CAAESysCreateInstanceForComponent::~CAAESysCreateInstanceForComponent()
{
  cout << "CAAESysCreateInstanceForComponent::~CAAESysCreateInstanceForComponent" << endl;
}

//------------------------------------------------------------------------------------

HRESULT __stdcall CAAESysCreateInstanceForComponent::CreateInstance(void ** oppv)
{
   CAASysComponent * pt = new CAASysComponent();
   if (NULL == pt) return(E_OUTOFMEMORY);

   *oppv = (void *)pt;

   return(S_OK);
}

The CAAESysCreateInstanceForComponent class states that it implements the CATICreatInstance interface thanks to the TIE_CATICreateInsatnce macro. This extension class is dedicated to this component, and the CATImplementClass macro declares that the CAAESysCreateInstanceForComponent class is code extension class, thanks to the CodeExtension keyword, and that it extends the component whose main class is CAASysComponent. The third parameter must always be set to CATBaseUnknown, makes no sense, and is unused for extensions. The CreateInstance method instantiates the CAASysComponent component main class. This method is called by the CATInstantiateComponent global function that is used by client applications to instantiate the component [4].

[Top]

Updating the Interface Dictionary

...
CAASysComponent CATICreateInstance  libCAASysComponentImpl
...

The interface dictionary declares that the CAASysComponent component implements the CAATICreateInstance interface and that the code to load into memory to use these interfaces is located in the libCAASysComponentImpl.m shared library or DLL. Note that the component main class name is used to refer to the component in the interface dictionary, and never the extension class names. Note also that the shared library or DLL to associate with the component/interface pair is the one that contains the code created by the call to the TIE macro (This is generally the same library than the one that contains the interface implementation code, since the TIE macro is usually included in the extension class source file.) This is because when a client asks a component for an interface pointer, the TIE class is instantiated first, and it either retrieves the existing instance of the appropriate extension class, or otherwise instantiates it.

Top]

Instantiating and Using the Component

// System Framework
#include "CATErrorDef.h"              // For the FAILED macro
#include "CATInstantiateComponent.h"  // For the global function to create the component
#include "CAAISysMyInterface.h"       // an interface implemented by the component

// C++ standard library    
#include <iostream.h>     // To display traces

int main()
{

  cout << "The CAASysComponentCreate Sample begins ....."<< endl;

 
  // -------------------------------------------------------------------------------
  // Creates the component and retrieves a CAAISysMyInterface interface pointer
  // -------------------------------------------------------------------------------

  CAAISysMyInterface * piSysMyInterfaceOnComponent = NULL; 
  HRESULT rc = ::CATInstantiateComponent( "CAASysComponent",  
                                         IID_CAAISysMyInterface,
                                         (void**)&piSysMyInterfaceOnComponent);   
                                          
  if ( FAILED (rc) )
  {
       cout << " Problem in the component Creation"<< endl;
       return 1 ;
  }

  //-----------------------------------------------------------------------
  //The component is created, and we can use the returned interface pointer 
  //-----------------------------------------------------------------------
  piSysMyInterfaceOnComponent->Print();

  //-----------------------------
  // Pointer no any longer needed
  //-----------------------------
  piSysMyInterfaceOnComponent->Release();
  piSysMyInterfaceOnComponent = NULL;


  cout << endl << "The CAASysComponentCreate Sample is finished."<< endl << endl ;

  return 0 ;
}

The CAASysComponent component is instantiated using the CATInstantiateComponent global function to which the following parameters should be passed:

CAASysComponent The component identifier that is also the component main class name
IID_CAAISysMyInterface The IID of the interface with which the client application wants to handle the component and to which a pointer is asked
piSysMyInterfaceOnComponent The pointer to that interface

Once the component is instantiated and handled using a pointer to the requested interface, the client application can go on using the component. No link is necessary between the client application and the component code. CATInstantiateComponent and the implemented interfaces isolates these two codes and are used as a contract between them to ensure that they will go on running as planned, and that modification to the component's code will not affect the client application and will ensure run time compatibility.

[Top]


In Short

This use case shows how to create a factory for a component. The main class declares the component inheritance and must C++-derive and OM-derive from CATBaseUnknown or from another component main class. The extension class that implement the CAATICreateInstance interface must C++-derive from CATBaseUnknown, while OM-inheritance makes no sense for it. The interface dictionary declares the correspondence between the component, the interfaces it implements, and the shared library or DLL to load for each interface. CATInstantiateComponent is used to instantiate the component and returns a pointer to the interface requested by the client application.

[Top]


References

[1] Creating Components
[2] Creating Interfaces
[3] Creating a Component Factory
[4] Using Components
[5] Building and Launching a CAA V5 Use Case
[6] Object Modeler Component and Implementation Inheritances
[Top]

History

Version: 1 [May 2002] Document created
[Top]

Copyright © 1994-2002, Dassault Systèmes. All rights reserved.