Understanding Applicative Container

Technical Article

Abstract

Any feature which is instantiated, is located within a container. When this persistent structure is created by the modeler's engine, it is called "container", when it is created by an application, DS or CAA, it is named "applicative container".  The goal of this article is to give you all necessary information to choose the right container to instantiate your CAA feature, and how to create, use and manage an applicative container.

What is a Container?

A Container is an Object Modeler component which has a late type. Generally the contained elements are created by a factory, an interface implemented by the container. Two example: CATIGSMFactory, implemented by CATPrtCont, a CATPart container, and CATGeoFactory , implemented by CGMGeom, a CATPart container too.

A container can contain features or CATBaseUnknown objects. The CGMGeom container contains geometrical objects which are not features. Nevertheless you will see in the Creation section, that by CAA you could only create container for features

There are two kinds of containers:

There are containers managed by the Modeler:

These container are created by applications. These applications can be DS or CAA.  An example of DS applicative containers are electrical containers. In the next sections you will have all the necessary information to create, use and manage correctly your own applicative container.

But the first question is when it is necessary to create an applicative container. It is purpose of the next section.

When Creating an Applicative Container?

You have just finished designing your new CAA feature, now the question is where to store the new Startup instantiations. The rule is as follows:

If you are in the second and third situation, the whole article is for you, but in the first case, the Access by Name and Parsing the Contents sections can be nevertheless useful.

How to Manage Applicative Container?

This section deals with the elementary functions: creating, retrieving and introspecting an applicative container. Nevertheless, the two sub-sections can be valid for DS containers too.

Creation

The only way to create an applicative container is the global function : CATCreateApplicativeContainer

HRESULT CATCreateApplicativeContainer(CATBaseUnknown ** oApplicativeContainer,
				      CATDocument * iDocument,
				      const CATIdent iContainerType,
				      const IID& iInterfaceId,
				      const CATIdent iContainerSuperType="",
				      const CATUnicodeString& iIdentifier="");

Have a look to each argument:

argument meaning
oApplicativeContainer It is the newly created container. It is a iInterfaceId interface pointer.
iDocument The document containing the new container.
iContainerType It represents the late type of the container. You will implement interfaces on this late type, like CATInit, but also factories to create the elements for the container.

If you do not want specify a late type, use the "CATFeatCont" string instead.

iInterfaceId The IID value of an interface implemented by the container. It can be CATBaseUnknown, CATIClientContainer, CATInit, or any other interface implemented by the container.  These three are the main generic ones.
iContainerSuperType An applicative container can only be a CATFeatCont or a  container deriving from CATFeatCont , so the possible values for iContainerSuperType depends on the iContainerType value:
  • if iContainerType = "CATFeatCont", iContainerSuperType can be "" or "CATFeatCont"
  • otherwise, iContainerSuperType can only be "CATFeatCont"
iIdentifier It represents the identifier name of the container, the name to be retrieved, see the next section. BUT take note that it is strongly recommended to use the same name as the late type value, that is iIdentifier is equal to iContainerType. This is mandatory for saving your container in 3D XML file.

If iIdentifier is an empty string, the name of the container is its late type.

Two containers of the same type can co-exist in the same stream, but their name must be different.

Generally you create an applicative container like this:

...
CATBaseUnknown *pContainer = NULL ;
CATDocument *pDoc =... ;
::CATCreateApplicativeContainer(pContainer,pDoc,
                             "MyContainerType",
                             IID_CATBaseUnknown,"CATFeatCont");                         
...

Access by Name

A container, applicative or not, can be retrieved from a CATDocument using its identifier name. This value is the sixth argument of the CATCreateApplicativeContainer , or if no value, its late type, the second argument of the same method. For DS container, refer to the modeler documentation if container's named are exposed.

The global function CATGetApplicativeContainer retrieves a container by its name

HRESULT CATGetApplicativeContainer(CATBaseUnknown ** oApplicativeContainer,
				   CATDocument* iDocument,
				   const IID& iInterfaceId,
				   const CATUnicodeString& iIdentifier);

Introspecting the Contents

The interface to use is CATIClientContainer. It is an interface implemented by any CATFeatCont container. We have seen previously that an applicative container can only contain features, so this interface is available for your applicative container.

Its unique method is ListMembers :

HRESULT ListMembers( const IID&  iIID, 
 const CATUnicodeString  ClientID, 
 CATListPtrCATBaseUnknown**  oLst)const =0  

This method retrieves within a container, all features implementing a given interface (IID). All the returned element can be used as IID interface pointer.

...
CATIClientContainer *pMyContainer = ....;
CATListPtrCATBaseUnknown * listfeatures = NULL ;
pMyContainer->ListMembers(IID_CATISpecObject,ClientIdValue, &listfeatures);
if (NULL != listfeatures )
{
     ...
     CATISpecObject *pCurrentElement = (*listfeatures)[i];
     ...
}

One you have through with the list, do nor forget to release its elements, and delete it.

The last not explained argument is "ClientID". This mandatory argument is the key of a Startup catalog. It means that CATIClientContainer can only retrieve features whose you know the Startup catalog key.

Standard DS Behavior Integration

By creating you own applicative container you benefit from all Feature modeler capabilities: persistency, introspection, sometimes automatic loading, and other facilities. But the modeler responsible of the CATDocument does not know the contents of your applicative containers, so it cannot expose the data as you would certainly like. That is the reason why, for some DS behavior (mostly interactive ones), which require the knowledge of  the applicative container contents, the modeler delegates to a special object this introspection. This special object is a Manager of Providers. Each applicative container, which want to be invoked for a DS behavior, should be previously declared to this manager. Each object which gives the behavior of one applicative container for one behavior is named a "Provider".

These possibilities are valid for Product Modeler and Mechanical Modeler.

For other modelers, have a look to their CAA documentation.

Applicative Container Loading and Activation

To be usable, an applicative container must be first either loaded in session, or just created , and then to be activated. The activation consists in to "give the hand" to the container in order to operate some actions of initialization. It will be explained in details next.

The loading and activation steps is depending on the context:

The activation is done through the Init method of the CATInit interface. This interface must be implemented on the late type of your applicative container, the second argument of the creation method.

This activation is done for each instance of applicative container. Consider this example:

Fig.2 Activation

The two streams (document) contain each one an instance of  the applicative container whose the late type is "Appl. Container 2".  Within Stream A, the container contains 2 features, and within Stream B , three others. When the activation of those containers will be requested, the Init method of the CATInit interface will be called for each one.

The Init Method Contents

The contents of this method generally contains these three steps, and in this order:

::SpecBindNativeFormat("iContainerType");

where iContainerType is the container type, see previous section.

If the first two can be useless, if you have no UI behaviors to implement, the last one is mandatory.

The GetRootContainer Method Contents

It depends on your applicative container contents. If the container contains a feature which is unique, and represents a root, this method can return it, otherwise the implementation can return NULL.

Volatile Container

A container is normally a persistent structure, but you can have a volatile container. It means that this specific container will not be saved when the stream is stored. It is the way to create "temporary object" while benefiting from Feature modeler capabilities.

Imagine you want to handle temporary objects during a session. It is possible using Object Modeler, but you will not take advantage of the feature modeler capabilities like undo/ redo functionalities.

A solution is to create an applicative container like it is described just above, but moreover to declare it  "non persistent" by implementing on it the CATIOsmVolatileContainer interface. When the stream is saved, the container will be not discarded.

In Short

In this article, we have described what is an application container, how it's created, introspected and activated.

References

History

Version: 1 [Oct 2007] Document created