3D PLM Enterprise Architecture

Middleware Abstraction - Object Modeler

Creating Components

Enabling your clients to instantiate your usable and scalable objects
Technical Article

Abstract

This article explains how to provide client applications with tools to create your implementation objects. It is a programmer's guide (how to) to show on simple examples the way an the code to write to create a global creation function, implement the CATICreateInstance interface, or a factory.


What Is a Component?

Components are the atoms that build an application. A component is a piece of executable code that you can't modify, but that you can use by means of the interfaces it exposes, that hides its implementation details, that can be replaced, even at run time, by another component exposing the same interfaces and performing the same job, and that ensures upward compatibility to client applications using it.

Compared to many past and often present monolithic applications, CATIA offers, since 1988 and its Version 3, an application programming interface that enables you to create applications, such as IUA commands, GII interactive functions, and batch applications. Since 1992 and CATIA Version 4, the same openness happens with data, and you can add your own application data to the CATIA data. Even if CATIA itself was a monolithic application, the applications and the data you added match partially the component definition, since you can reuse your applications on newer CATIA releases without the need of rebuilding them, and your application data without migrating it.

With the help of the object-oriented technology, data and software make a whole named object, and components are now made of objects. Objects provide the features required by components:

We'll see in this article what is a CAA V5 component made up of, how you can create them as CAA V5 component providers, and how you can use and extend them as client application programmers.

[Top]

What Is a CAA V5 Component?

Client application programmers have usually a logical view of CAA V5 components and see a CAA V5 component as an object exposing interfaces. On the opposite, the component supplier has a detailed physical view of the CAA V5 component, that is, he/she knows which C++ classes make up the component, how these C++ classes are assembled to build the component, and which interface is implemented by which class.

[Top]

The Client Application Programmer Logical View

As a client application programmer, you often need to create components and manipulate them using the interfaces they expose, whatever the way and the complexity of their internal structure. For example, when you need to create a circle, you call the circle component factory which creates a circle instance and returns a pointer to the CATICircle interface. Then you need to move the circle, and you call QueryInterface to get a pointer to the CATIMove interface for this circle component instance. Then you may need to draw it, or modify its display attributes. Whenever you need to do something to this circle, you ask for a pointer to the appropriate interface if you haven't one already, and you use this pointer to call the methods exposed by this interface for this component.

Fig 1: The Client Application Programmer Sees a Simple and Single Component

Your view of the component you manipulate is a logical view that makes you see the component as if it were simple and self-contained.

[Top]

The Component Supplier Physical View

As a component supplier, your view of the component may be quite different. You may want to take advantage of the code factorization capabilities offered by CAA V5, and make full use of extensions. This makes it possible for you to design and code a single application component like a circle as several C++ classes, one being the circle main implementation class, and the others extension classes of this main implementation class, each of these classes implementing one or several interfaces through which the client application programmer will manipulate the circle, seeing it as a simple and single component.

For example, the classes making up the circle could be designed as shown on Fig 2.

Fig 2: The Component Supplier Sees several Linked Classes

According to this design, up to four classes can be instantiated when the client application programmer manipulates a circle, but everything happens as if only one component were manipulated.

[Top]

What Is an Extension

The CAA V5 object model modularity and scalability is offered through extensions. This is a very powerful means to build CAA V5 components from C++ objects and to supply software updates without implying to rebuild the client applications.

An extension to a main implementation class is a separate class that is attached to the main implementation class and which extends it to implement additional interfaces that this main implementation class does not implement itself. Extension common usage is to share the implementation of interfaces between several components, or to implement a new interface which did not exist at the time the framework was released and which was added after. This helps a lot for modularity and scalability.

Extensions are C++ classes which must have the CATBaseUnknown class among its base class, and that must directly OM-derive from CATBaseUnknown. They can be of the following types:

The extension class and the class it is an extension of are declared in the extension source file using the macro CATImplementClass. The link between the extension and the interface it implements is managed through the dictionary. The shared library which contains the code for the extension is also included.

The class that implement interfaces as an extension of a component is created automatically when a pointer to an interface the extension implements is requested by QueryInterface. So you don't need to worry about a factory of global function to create extensions.

Note that the extension is not a recursive concept. There are no extensions of extensions.

[Top]

Data Extensions

A data extension is a C++ class that contains data members and methods. Suppose that our object MyObject is already used by numerous clients and that we want to add data that it doesn't hold already. If we supply a new version of our object which implements an additional interface for this data, the clients will be very happy to get a new functionality, but may become unhappy when we'll tell them to rebuild their applications, even if they don't use this interface. To overcome this problem, we can use a data extension as follows:

Fig 3: A Component Made up of an Implentation and a Data Extension Classes

The new interface CATIData is implemented by the separate C++ class MyDataExtension with methods to access the data and data members to store it. There is no need to rebuild the client applications when you deliver the data extension, since the MyObject class has not changed from these applications standpoint. Only client applications that want to take advantage of the update need of course to be modified and rebuilt.

Lifecycle: A call to QueryInterface against the object for an interface implemented by a data extension of this object creates the data extension instance, or uses the existing one. The data extension is deleted only when the object of which it is an extension is also deleted, that is when all the reference counts of the object and of all its extensions reach 0.

The idl file for CATIData is as follows:

// IDL encoded interface

#pragma ID CATIData "DEC:7db286f1-218d-0000-0280020a86000000"
interface CATIData : CATBaseUnknown {
#pragma PROPERTY Length
  HRESULT get_Length(out int oLength);
  HRESULT put_Length(in int iLength);
};

The resulting header file CATIData.h is as follows:

// C++ generated interface class header file
#include "CATBaseUnknown.h"
extern IID IID_CATIData;
class CATIData : CATBaseUnknown {
  CATDeclareInterface;
  public :
    virtual HRESULT __stdcall get_Length(int * oLength) = 0;
    virtual HRESULT __stdcall set_Length(int iLength) = 0;
};

The resulting source file CATIData.cpp is as follows:

// C++ generated interface class source file
#include "CATIData.h"
IID IID_CATIData = { 0x7db286f1, 0x218d, 0x0000,
    {0x02, 0x80, 0x02, 0x0a, 0x86, 0x00, 0x00, 0x00} };
CATImplementInterface(CATIData, CATBaseUnknown);

The MyDataExtension class implements this interface:

#include "CATBaseUnknown.h"

class MyDataExtension : public CATBaseUnknown {
  CATDeclareClass;
  public :
    MyDataExtension();
    virtual ~MyDataExtension();
    virtual HRESULT __stdcall get_Length(int * oLength);
    virtual HRESULT __stdcall set_Length(int iLength);
  private :
    int _Length;
};

The CAAEDataExtension class source file is as follows:

#include "CAAEDataExtension.h"

CATImplementClass(CAAEDataExtension, // Extension class name
                  DataExtension,     // Data extension
                  CATBaseUnknown,    // Always OM-derive extensions from CATBaseUnknown
                  MyObject);         // Main class of the extended component

#include "TIE_CATIData.h"
TIE_CATIData(CAAEDataExtension);

CAAEDataExtension::CAAEDataExtension() {}
CAAEDataExtension::~CAAEDataExtension() {} 

HRESULT CAAEDataExtension::get_Length(int * oLength)
{ oLength = _Length; return S_OK; }

HRESULT CAAEDataExtension::set_Length(int iLength)
{ _Length = iLength; return S_OK; }

The CATImplementClass macro states that the class CAAEDataExtensionis a data extension and that extends the MyObject class. The third argument that declares the component from which the current one OM-derives makes sense only for component main classes and must always be set to CATBaseUnknown with an extension.

[Top]

Code Extensions

A code extension is an extension that contains only methods, and no data. At run-time, for a given code extension, only one instance of this code extension exists, whatever the number of existing objects this code extension extends.

As for data extensions, there is no need to rebuild client applications when the code extension is supplied.

You code a code extension as a data extension, and just use CodeExtension instead of DataExtension as the second parameter of the CATImplementClass macro in the code extension class source file, as follows:

...
CATImplementClass(CAAECodeExtension,
                  CodeExtension,
                  CATBaseUnknown,
                  MyObject);
...

Lifecycle: Once created for a given object instance, the code extension is never deleted and is used for all the instances of the same object.

[Top]

Sharing Extensions

Sharing an extension makes several classes implement the interfaces the extension itself implements, and not only one class as shown in the above sections about extensions. This is another step in code factorization and reusability, and in code scalability.

There are two ways for sharing extensions. The first way is to let the extension itself declare of which classes it is an extension. This is very handy if you have existing classes for which you want to add an additional behavior by means of the interfaces implemented in the extension. You don't need to rebuild the existing classes, just supply the extension. The second way is to declare the extension support in the classes that are extended by the extension. This is very handy if you have an existing extension and if you want to declare it as an extension of new classes. You don't need to rebuild the extension, just supply the new classes.

Declare that an extension class is an extension for several classes in the extension class source file (.cpp) as follows:

CATBeginImplementClass(MyExtensionClassName,    // Begin declaration
                       DataExtension,
                       CATBaseUnknown,
                       TheFirstClassIExtend);
CATAddClassExtension(TheSecondClassIExtend);
CATAddClassExtension(TheThirdClassIExtend);
...
CATAddClassExtension(TheLastClassIExtend);
CATEndImplementClass(MyExtensionClassName);     // End declaration

The CATBeginImplementClass macro replaces the CATImplementClass macro. The CATAddClassExtension macro is used to add a class to the extended classes, and the CATEndImplementClass macro ends the declaration sequence for the concerned extension.

You declare an existing extension in a new class in this class source file (.cpp) as follows:

CATSupportImplementation(ExtensionClassName,
                         MyClassName,
                         ImplementedInterface);

The CATSupportImplementation macro allows addition of existing extensions incrementally to new classes.

[Top]

What Are the TIE and the BOA?

In the code example above, when implementing CATIData, the following lines were used:

...
CATImplementClass(CAAEDataExtension, // Extension class name
                  DataExtension,     // Data extension
                  CATBaseUnknown,    // Base component - Always OM-derive TIE extensions from CATBaseUnknown
                  MyObject);         // Implementation class of the extended component

#include "TIE_CATIData.h"
TIE_CATIData(CAAEDataExtension);
...

Let's detail them:

The TIE is the technology promoted by CAA V5 to handle interfaces at run time. Nevertheless, in some scenarios where performance is critical, instantiating an intermediate object may be costly. For example, if a component is instantiated thousands of times and if a pointer to a given interface is requested against each component instance, thousands of TIE objects are created and may lead to memory allocation problems. To avoid this, CAA V5 proposes an alternate solution: the BOA.

BOA stands for Basic Object Adapter. The BOA technology makes QueryInterface return a pointer to the class that implements the interface rather than a pointer to an intermediate class. The BOA saves a class instance per component in scenarios such as the one described above. Even if a pointer to the implementing class is returned, it is returned as an interface pointer, and there is not more coupling between interface and implementation than with the TIE. The client application does not know which class implements the interface, has no build time link with its header file or module, and can thus only call the methods exposed by this interface.

To implement CATIData using the BOA instead of the TIE:

Note that since the class implementing the interface using the BOA must derive from the interface, and that CAA V5 does not support multi-inheritance, a given class can BOA-implement only one interface, the others being TIE-implemented. So carefully choose the appropriate interface to BOA-implement if your class implements several interfaces. In addition, BOA is not available with CodeExtension type classes.

CAA V5 BOA candidate interfaces are the U4 and U5 labelled interfaces [3], that is, the interfaces you implement and that V5 calls onto your components. U4 means that you implement the interface by deriving a V5 supplied adapter class and override a part of the methods. U5 means that you write the code for all the methods of the interface. While there is no BOA restriction with U5 interfaces, pay attention with U4 interfaces. A U4 interface must be BOA-enabled, that is, its adapter must derive from it, otherwise BOA cannot be used for that interface. Among the U4 interfaces, some are BOA-enabled, and some are not. To know whether a U4 interface is BOA-enabled, check BOA information section in the interface documentation.

[Top]


In Short

A component is an object that implements interfaces. It is seen as a single object from the component user standpoint, but can be implemented as several C++ objects.

An extension is an object that is part of a component to provide it a given behavior by implementing one or several interfaces. The extension is not seen from the client application, but is handled using a pointer to an interface it implements. An extension is also the means to add behavior to a component without modifying already existing client applications.

The TIE and the BOA are the CAA V5 technologies to implement interfaces. A class can implement many interfaces using the TIE, but only one of them can be implemented using the BOA.

[Top]


References

[1] Creating Interfaces
[2] Using Components
[3] CAA V5 Resource Exposition, Usage, Deprecation, and Stability
[Top]

History

Version: 2 [Oct 2003] BOA added
Version: 1 [Jan 2000] Document created
[Top]

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