API_BEGIN and API_END Macros
List of: Discussion Topic
Subjects: Extending ACIS, C++ Interface
Contents: Application Development Manual

The purposes of an API_BEGIN and API_END block are to:


1. Protect the contained logic block with ACIS exception handling.


2. Provide rollback behavior in the event a modeling operation fails.

The API_BEGIN macro declares a variable "result" of class "outcome". When performing modeling operations within an API_BEGIN and API_END block, the result variable should be used to contain the success or failure of those operations. Take for example the following fictional customer function, which returns true or false if the following set of operations succeeds/fails:

bool do_something(BODY *& retbody)
{

bool ret;

BODY *prism = NULL;

BODY *cone = NULL;


API_BEGIN


result = api_make_prism(..., prism);


if(result.ok())


result = api_make_frustum(..., cone);


// prism is tool, cone is blank. The result of

// this call is the blank (cone); the tool (prism)

// is deleted.

if(result.ok())


result = api_intersect(prism, cone);


// If a NULL body is returned, then there was no

// overlap - we consider this failure. Force a rollback

// by setting "result" to a failing value.

if (cone == NULL)


result = outcome(API_FAILED);


API_END


// Setup our return values.

ret = result.ok();

retbody = cone;


return ret;
}

There are some significant points to note about this simple example:

The variable result is used for determining the success or failure of the entire API_BEGIN/API_END logic block. It is even set to API_FAILED if the prism and cone don't intersect. By doing this, the API_END will examine result and, if it is non-zero, then rolls back all changes (assuming this is the outermost API_END).
In the event of any type of failure, no cleanup is needed. The rollback will perform all cleanup.
There are no return's or goto's inside the API_BEGIN/API_END block. This is important because once an API_BEGIN block is entered, it must be exited through it's corresponding API_END block.
Let us take this example one step further by considering how this routine is called:

void main(void)
{

API_BEGIN


BODY *bod;

bool r = do_something(bod);


result = (r == true) : outcome(0) ? outcome(API_FAILED);


// If the result is not ok, no cleanup is needed; all

// results will be rolled back when we pass through API_END.

if (result.ok())


api_del_entity(bod);


API_END
}

This illustrates that nesting of API_BEGIN/API_END blocks is perfectly acceptable. However, there are important behavioral differences:

If any failures occur within do_something, it's API_END does NOT rollback the changes. The rollback always occurs at the outermost API_END, which is now the API_END in main.
It is important for do_something to propagate the knowledge of success or failure using it's bool return value. It allows main() to realize success or failure and set it's result appropriately. The knowledge of success or failure must be propagated upward through API_BEGIN/API_END blocks to ensure that the rollback occurs at the outermost API_END.
PDF/APPDEV/08EXT.PDF
HTM/DATA/ACIS/APPDEV/08EXT/0018.HTM