3D PLM PPR Hub Open Gateway

Feature Modeler

Referencing Features by Features

Working with referenced attributes
Use Case

Abstract

This article discusses the CAAOsmReferencedAttr use case. This use case explains how to load an existing catalog containing StartUps, how to create a document to contain new features, how to retrieve StartUps and create new features by instantiating them, how to add features as referenced attributes of other features and how to save the new document.


What You Will Learn With This Use Case

This use case is intended to help you understand the basics of working with referenced attributes. Its main intent is to explain the nature of referenced attributes, how to create them and how to assign them to features. Through this use case, you will also learn some important aspects recommended when programming with features. Specifically, you will learn how to:

Before getting to the use case itself, it is important to get an understanding of what a feature object is and how it is created [1].

[Top]

The CAAOsmReferencedAttr Use Case

CAAOsmReferencedAttr is a use case of the CAAObjectSpecsModeler.edu framework that illustrates ObjectSpecsModeler framework capabilities.

[Top]

What Does CAAOsmReferencedAttr Do

The goal of CAAOsmReferencedAttr is to illustrate adding features to features as tk_specobject attributes. These features are then said to be "referenced". This use case uses the catalog defined in the CAAOsmCatalogSU use case [2] which contains StartUps based on the "book" example.

In this use case, a new feature, "CAAOsmPublisher1" is instantiated from the "CAAOsmPublisher" StartUp and its attributes are valuated."CAAOsmPublisher1" is added as a tk_specobject type of attribute to other features, "CAAOsmNovel1" and "CAAOsmNovel2". In other words, we see that two different novels have the same publisher.

To enrich the example, a new feature, "CAAOsmPublisher2" is created by instantiating the "CAAOsmPublisher" StartUp once more. Its attributes are valuated and it is added as a tk_specobject to another new feature, "CAAOsmDictionary1": "CAAOsmDictionary1" is not published by the same publishing house as are "CAAOsmNovel1" and "CAAOsmNovel2". Here is a relational schematic view of the operations performed in this use case:

Next, this article demonstrates that the notion of "parent" for a referenced feature has no meaning. If a "parent" feature is deleted, as is "CAAOsmDictionary1", the referenced feature remains intact and it can continue to be assigned to any number of other features. Note that this behavior is not true for "aggregated" features.

[Top]

How to Launch CAAOsmReferencedAttr

To launch CAAOsmReferencedAttr , you will need to set up the build time environment, then compile CAAOsmReferencedAttr along with its prerequisites, set up the run time environment, and then execute the sample. 

mkrun -c "CAAOsmReferencedAttr CAAOsmCatalogSU.CATfct DocumentStorageName.CATPart"

This is fully described in the referenced article [3]. When launching the use case, you must pass the following arguments:

[Top]

Where to Find the CAAOsmReferencedAttr Code

CAAOsmAggregatedAttr code is located in the CAAOsmReferencedAttr.m use case module of the CAAObjectSpecsModeler.edu framework:

Windows InstallRootDirectory\CAAObjectSpecsModeler.edu\CAAOsmReferencedAttr.m
Unix InstallRootDirectory/CAAObjectSpecsModeler.edu/CAAOsmReferencedAttr.m

where InstallRootDirectory is the root directory of your CAA V5 installation. It is made of a unique source file named CAAOsmReferencedAttr.cpp.

[Top]

Step-by-Step

There are ten logical steps in CAAOsmReferencedAttr:

We will now comment each of these sections by looking at the code.

[Top]

Prolog

See the referenced article [4<]/a> for a detailed description of the steps to go through when creating a new document.

In this use case, we create a new "Part" document: CATDocument *pDoc, and retrieve its root container: CATIContainer *piRootContainer.

[Top]

Loading the Catalog

Loading the catalog means opening the catalog document and getting a CATICatalog handle that will be needed in order to retrieve StartUps from the catalog.

CATUnicodeString stgName = argv[1];
CATICatalog *piCatalog;
CATUnicodeString clientId("CAAOsmClientId");
rc = ::AccessCatalog (&stgName,
                      &clientId,
                      piRootContainer,
		      &piCatalog); 
	
if (SUCCEEDED(rc)) cout << "Catalog accessed OK" << endl << flush;
else
{
   cout << "ERROR on AccessCatalog" << endl << flush;
   piRootContainer -> Release();
   return 5;
}

To open a catalog, use the AccessCatalog global function that takes the following arguments:

[Top]

Creating the Feature "CAAOsmPublisher1"

  1. Retrieve "CAAOsmPublisher" StartUp
    CATBaseUnknown *pPublisherSU = NULL;
    CATUnicodeString publisherSUType("CAAOsmPublisher");
    rc = piCatalogOnContainer -> RetrieveSU(&pPublisherSU,
                                            &publisherSUType,
    	                                "CATISpecObject");
    if (NULL != pPublisherSU) cout << "CAAOsmPublisher StartUp retrieved OK" << endl << flush;
    else
    {
       (Process ERROR:  Release pointers and return.)
    }
    // Get a CATISpecObject handle on the CAAOsmPublisher StartUp
    
    CATISpecObject *piPublisherSU = (CATISpecObject*) pPublisherSU;

    A StartUp is retrieved from the catalog using the CATICatalog::RetrieveSU method. This method returns a CATBaseUnknown pointer in pPublisherSU which is directly cast into a CATISpecObject pointer (piPublisherSU). The CATBaseUnknown pPublisherSU pointer must be released when no longer needed.

  2. Get CATISpecAttrAccess handle
    CATISpecAttrAccess *piSpecAttrAccessOnPubSU = NULL;
    rc = piPublisherSU -> QueryInterface(IID_CATISpecAttrAccess,
                                         void**) &piSpecAttrAccessOnPubSU);
    if (FAILED(rc)) 
    {
       (Process ERROR:  Release pointers and return.)
    }

    Once the StartUp has been retrieved, it is a good idea to immediately get the attribute keys that will be needed later on. These attribute keys remain globally available once they have been accessed. This means that valuating the attributes of any number instances of this StartUp will be more direct since there will be no need to access the attribute before valuating it. In order to get the StartUp's attribute keys, we first get a CATISpecAttrAccess handle on the StartUp.

  3. Get attribute keys
    ATISpecAttrKey *piKeyPublisherName = piSpecAttrAccessOnPubSU ->
    		GetAttrKey("PublisherName");
    if (NULL == piKeyPublisherName)
    {
       (Process ERROR:  Release pointers and return.)
    }
    
    CATISpecAttrKey *piKeyPublisherAddress = piSpecAttrAccessOnPubSU ->
    		GetAttrKey("PublisherAddress");
    if (NULL == piKeyPublisherAddress)
    {
       (Process ERROR:  Release pointers and return.)
    }
    	
    piSpecAttrAccessOnPubSU -> Release();

    Using the CATISpecAttrAccess::GetAttrKey, we get a CATISpecAttrKey handle to each attribute that will be valuated.

  4. Instantiate "CAAOsmPublisher" StartUp
    CATUnicodeString publisher1("CAAOsmPublisher1");
    CATISpecObject *piPubInst1 = piPublisherSU -> 
    		Instanciate(publisher1,
    		            piRootContainer);
    if (NULL != piPubInst1) cout << "CAAOsmPublisher SU instance 1 created OK" << endl << flush;
    else 
    {
       (Process ERROR:  Release pointers and return.)
    }

    Finally, a new feature, "CAAOsmPublisher1" is created in the root container by instantiating the StartUp "CAAOsmPublisher".

  5. Valuate "CAAOsmPublisher1" attributes
    CATISpecAttrAccess *piSpecAttrAccessOnPub1 = NULL;
    rc = piPubInst1 -> QueryInterface(IID_CATISpecAttrAccess, 
                                      (void**) &piSpecAttrAccessOnPub1);
    if (FAILED(rc))
    {
       (Process ERROR:  Release pointers and return.)
    }
    
    piSpecAttrAccessOnPub1 -> SetString(piKeyPublisherName,
                                        "Collins Press");
    piSpecAttrAccessOnPub1 -> SetString(piKeyPublisherAddress,
                                        "London");
    piSpecAttrAccessOnPub1 -> Release();

    The new feature's attributes are valuated using a CATISpecAttrAccess handle and SetString.

[Top]

Creating the Feature "CAAOsmNovel1"

Now that "CAAOsmPublisher1" has been created, it will be assigned as a referenced attribute to a new feature, "CAAOsmNovel1". So, let's create "CAAOsmNovel1".

  1. Retrieve "CAAOsmNovel" StartUp
    CATBaseUnknown *pNovelSU = NULL;
    CATUnicodeString novelSUType("CAAOsmNovel");
    rc = piCatalogOnContainer -> RetrieveSU(&pNovelSU,
                                            &novelSUType,
    		                        "CATISpecObject");
    if (pNovelSU) cout << "CAAOsmNovel StartUp retrieved OK" << endl << flush;
    else
    {
       (Process ERROR:  Release pointers and return.)
    }
    // Get a CATISpecObject handle on the CAAOsmNovel StartUp
    
    CATISpecObject *piNovelSU = (CATISpecObject*) pNovelSU;

    The "CAAOsmNovel" StartUp is retrieved using the RetrieveSU method of CATICatalog.

  2. Get "CAAOsmNovel" StartUp's attribute keys
    CATISpecAttrAccess *piSpecAttrAccessOnNovel = NULL;
    rc = piNovelSU -> QueryInterface(IID_CATISpecAttrAccess,
                                     (void**) &piSpecAttrAccessOnNovel);
    if (FAILED(rc))
    {
       (Process ERROR:  Release pointers and return.)
    } 
    
    CATISpecAttrKey *piKeyNovelPublisher = piSpecAttrAccessOnNovel ->
    		GetAttrKey("BookPublisher");
    if (NULL == piKeyNovelPublisher)
    {
       (Process ERROR:  Release pointers and return.)
    }

    We get a CATISpecAttrAccess handle in order to get the attribute keys from the StartUp using GetAttrKey.

  3. Instantiate "CAAOsmNovel" StartUp
    CATUnicodeString novel1("CAAOsmNovel1");
    CATISpecObject *piNovelInst1 = piNovelSU -> 
    		Instanciate(novel1,
    		            piRootContainer);
    if (piNovelInst1) cout << "CAAOsmNovel SU instance 1 created OK" << endl << flush;
    else
    {
       (Process ERROR:  Release pointers and return.)
    }

    And now, we can instantiate the StartUp and create a new feature "CAAOsmNovel1":

[Top]

Assigning "CAAOsmPublisher1" as a Referenced Feature

  1. Assign "CAAOsmPublisher1" to "CAAOsmNovel1" as a referenced feature
    CATISpecAttrAccess *piSpecAttrAccessOnNov1 = NULL;
    rc = piNovelInst1 -> QueryInterface(IID_CATISpecAttrAccess,
                                        (void**) &piSpecAttrAccessOnNov1);
    piNovelInst1 -> Release();
    if (FAILED(rc))
    {
       (Process ERROR:  Release pointers and return.)
    }
    
    piSpecAttrAccessOnNov1 -> SetSpecObject(piKeyNovelPublisher,
    	                                piPubInst1);
    piSpecAttrAccessOnNov1 -> Release();

    The attribute "BookPublisher" of the StartUp "CAAOsmNovel" has been defined as a tk_specobject. This means that this attribute must be valuated by a feature object. We assign the feature "CAAOsmPublisher1" as a referenced attribute (of tk_specobject type) of "CAAOsmNovel1". This is done using the SetSpecObject method of CATISpecAttrAccess to which we pass the attribute key and the CATISpecObject handle to the feature "CAAOsmPublisher1".

  2. Assign "CAAOsmPublisher1" to "CAAOsmNovel2" as a referenced feature
    CATUnicodeString novel2("CAAOsmNovel2");
    CATISpecObject *piNovelInst2 = piNovelSU ->
    		Instanciate(novel2,
    		            piRootContainer);
    pNovelSU -> Release();
    if (piNovelInst2) cout << "CAAOsmNovel SU instance 2 created OK" << endl << flush;
    else
    {
       (Process ERROR:  Release pointers and return.)
    }
    
    // Valuate attribute "BookPublisher" for "CAAOsmNovel2" with the new instance of
    // "CAAOsmPublisher" ("CAAOsmPublisher1")
    
    CATISpecAttrAccess *piSpecAttrAccessOnNov2 = NULL;
    rc = piNovelInst2 -> QueryInterface(IID_CATISpecAttrAccess,
                                        (void**) &piSpecAttrAccessOnNov2);
    if (FAILED(rc))
    {
       (Process ERROR:  Release pointers and return.)
    } 
    
    piSpecAttrAccessOnNov2 -> SetSpecObject(piKeyNovelPublisher,
                                            piPubInst1);
    
    piKeyNovelPublisher -> Release();
    piNovelInst2 -> Release();
    piSpecAttrAccessOnNov2 -> Release();
    piPubInst1 -> Release();

    Since "NovelPublisher" is of type tk_specobject, this means that the feature assigned to "CAAOsmNovel1" as a referenced attribute can be assigned to other features as well. To show this, we create a new feature, "CAAOsmNovel2" and assign "CAAOsmPublisher1" to it.

    As you can see, the novels "CAAOsmNovel1" and "CAAOsmNovel2" both have the same publisher.

[Top]

Creating the Feature "CAAOsmPublisher2"

CATUnicodeString publisher2("CAAOsmPublisher2");
CATISpecObject *piPubInst2 = piPublisherSU -> 
		Instanciate(publisher2,
		            piRootContainer);
pPublisherSU -> Release();
if (piPubInst2) cout << "CAAOsmPublisher SU instance 2 created OK" << endl << flush;
else
{
   (Process ERROR:  Release pointers and return.)
}
CATISpecAttrAccess *piSpecAttrAccessOnPub2 = NULL;
rc = piPubInst2 -> QueryInterface(IID_CATISpecAttrAccess,
                                  (void**) &piSpecAttrAccessOnPub2);
if (FAILED(rc))
{
   (Process ERROR:  Release pointers and return.)
}	
	
piSpecAttrAccessOnPub2 -> SetString(piKeyPublisherName,
                                    "Larousse");
piSpecAttrAccessOnPub2 -> SetString(piKeyPublisherAddress, 
                                    "Paris");

piKeyPublisherName -> Release();
piKeyPublisherAddress -> Release();
piSpecAttrAccessOnPub2 -> Release();

Now, to further our example, we create a new feature, "CAAOsmPublisher2" from the "CAAOsmPublisher" StartUp and we valuate its attributes with the names and address of another publishing house.

[Top]

Creating the Feature "CAAOsmDictionary1"

CATBaseUnknown *pDictionarySU = NULL;
CATUnicodeString dictionarySUType("CAAOsmDictionary");
rc = piCatalogOnContainer -> RetrieveSU(&pDictionarySU,
                                        &dictionarySUType,
                                        "CATISpecObject");
if (pDictionarySU) cout << "CAAOsmDictionary StartUp retrieved OK" << endl << flush;
else 
{
   (Process ERROR:  Release pointers and return.)
}
// Get a CATISpecObject handle on the CAAOsmDictionary StartUp

CATISpecObject *piDictionarySU = (CATISpecObject*) pDictionarySU;
	
// Get the dictionary's attribute key "BookPublisher"

CATISpecAttrAccess *piSpecAttrAccessOnDict = NULL;
rc = piDictionarySU -> QueryInterface(IID_CATISpecAttrAccess, 
                                      (void**) &piSpecAttrAccessOnDict);
if (FAILED(rc))
{
   (Process ERROR:  Release pointers and return.)
}	
	
CATISpecAttrKey *piKeyDictPublisher = piSpecAttrAccessOnDict ->
		GetAttrKey("BookPublisher");
if (NULL == piKeyDictPublisher)
{
   (Process ERROR:  Release pointers and return.)
}
piSpecAttrAccessOnDict -> Release();

// Get an instance of the CAAOsmDictionary StartUp

CATUnicodeString dictionary1("CAAOsmDictionary1");
CATISpecObject *piDictInst1 = piDictionarySU -> 
		Instanciate(dictionary1,
		            piRootContainer);
if (piDictInst1) cout << "CAAOsmDictionary SU instance 1 created OK" << endl << flush;
else
{
   (Process ERROR:  Release pointers and return.)
}

We also create a new feature, "CAAOsmDictionary1" from the "CAAOsmDictionary" StartUp and we acquire the attribute keys.

[Top]

Assigning "CAAOsmPublisher2" as a Referenced Feature

CATISpecAttrAccess *piSpecAttrAccessOnDict1 = NULL;
rc = piDictInst1 -> QueryInterface(IID_CATISpecAttrAccess,
                                   (void**) &piSpecAttrAccessOnDict1);
if (FAILED(rc))
{
   (Process ERROR:  Release pointers and return.)
} 

piSpecAttrAccessOnDict1 -> SetSpecObject(piKeyDictPublisher,
                                         piPubInst2);

piSpecAttrAccessOnDict1 -> Release();

Now, we assign "CAAOsmPublisher2" to "CAAOsmDictionary1" as a referenced feature in order to show that different types of "CAAOsmBooks", such as dictionaries and novels, can have different publishers.

[Top]

Illustrating that "CAAOsmPublisher2" Is Not Tied to a "Parent" Feature

  1. Get the father of "CAAOsmPublisher2"
    CATISpecObject *piPubInst2Father = piPubInst2 -> GetFather();
    if (NULL == piPubInst2Father) cout << "OK:  Feature CAAOsmPublisher2 does not have a father!" << endl << flush;
    else 
    {
        cout << "ERROR:  Feature CAAOsmPublisher2 should not have a father and it does!" << endl << flush;
        piPubInst2Father -> Release();
    }

    A feature used as a referenced attribute does not have a "parent": it exists independently of any other feature. Therefore, the method GetFather has no meaning when applied to a referenced feature: it returns a NULL.

  2. Delete "CAAOsmDictionary1"
    LifeCycleObject *pDict = NULL;
    rc = piDictInst1 -> QueryInterface(IID_LifeCycleObject,
                                       (void**) &pDict);
    if (FAILED(rc))
    {
       (Process ERROR:  Release pointers and return.)
    }
    else pDict -> remove();
    
    pDict -> Release();
    piDictInst1 -> Release();

    If "CAAOsmDictionary1" is deleted, "CAAOsmPublisher2" can still be assigned to other features as a referenced attribute. So, let's delete "CAAOsmDictionary1" and see. This is done using a LifeCycleObject handle that we acquire on the "CAAOsmDictionary1" feature. Using this handle, we perform a remove in order to delete the feature.

  3. Create "CAAOsmDictionary2"
    CATUnicodeString dictionary2("CAAOsmDictionary2");
    CATISpecObject *piDictInst2 = piDictionarySU -> 
    		Instanciate(dictionary2,
    		            piRootContainer);
    pDictionarySU -> Release();
    if (piDictInst2) cout << "CAAOsmDictionary SU instance 2 created OK" << endl << flush;
    else
    {
       (Process ERROR:  Release pointers and return.)
    }

    To show that "CAAOsmPublisher2" is not also deleted along with "CAAOsmDictionary1", assign it to a new instance of "CAAOsmDictionary". In order to do this, first we must create a new instance of "CAAOsmDictionary" that we will call "CAAOsmDictionary2".

  4. Assign "CAAOsmPublisher2" to "CAAOsmDictionary2" as a referenced feature
    CATISpecAttrAccess *piSpecAttrAccessOnDict2 = NULL;
    rc = piDictInst2 -> QueryInterface(IID_CATISpecAttrAccess, 
                                       (void**) &piSpecAttrAccessOnDict2);
    piDictInst2 -> Release();
    if (FAILED(rc))
    {
       (Process ERROR:  Release pointers and return.)
    }	
    	
    piSpecAttrAccessOnDict2 -> SetSpecObject(piKeyDictPublisher,
                                             piPubInst2);
    	
    piKeyDictPublisher -> Release();
    piSpecAttrAccessOnDict2 -> Release();
    piPubInst2 -> Release();

    And now, we can assign "CAAOsmPublisher2" to the new "CAAOsmDictionary2" feature using SetSpecObject.

[Top]

Epilog.

Before proceeding to save the document, be sure to release any remaining pointers that will no longer be used:

piRootContainer -> Release();
piCatalogOnContainer -> Release();

See the referenced article [4] for a detailed description of the steps to go through when saving a document.

[Top]


In Short

This use case has demonstrated how to use referenced attributes. Specifically, it has illustrated:

[Top]


References

[1] Feature Modeler Conceptual Overview
[2] Creating StartUps in Catalogs
[3] Building and Launching a CAA V5 Use Case
[4] Creating a New Document
[Top]

History

Version: 1 [Feb 2000] Document created
Version: 2 [Nov 2000] Document modified
[Top]

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