How do I effectively handle errors thrown by ITK calls in Teamcenter server customization code?
In the C ITK APIs, a function typically returns an integer value to denote success/failure. Zero (ITK_ok
) is typically treated as success and non-zero is treated as failure. In case of a failure, the developer must cleanup resources used (e.g., free memory).
I have seen a lot of code written by customization developers using a macro. Even I did that when I first wrote my first Teamcenter ITK program:
#define ITK(A) { \
iFail = A; \
if (iFail != ITK_ok) { \
HANDLE THE ERROR \
} \
}
I defined a macro like that and used it everywhere I made an ITK function call. For example:
ITK(AOM_ask_value_logical(myTag, "attributeName", &attributeValue));
It compares the output of every function call with ITK_ok
and does something. There is nothing wrong with it. But many things could actually go wrong, and it can difficult to understand.
I have even seen people doing this:
if (ITK_ok != AOM_ask_value_logical(myTag, "attributeName", &attributeValue))
{
// DO SOMETHING
}
Or
int result = ITK_ok
result = AOM_ask_value_logical( myTag, "attributeName", &attributeValue);
if (ITK_ok != result)
{
// DO SOMETHING
}
I mean, there is nothing wrong with this one. But doesn’t it increase your code size? Don’t you see the duplicity?
Later, I realized that we could do this in more elegant simple way. C++ way using classes and overloaded operator. And later I even found that there is something called as ResultCheck
in OOTB (out-of-the-box) Teamcenter.
All you need to do is include a header file and use a class from it.
#include <base_utils/ResultCheck.hxx>
This file declares the ResultCheck
class with overloaded assignment operator. This file is included in Teamcenter kit, you can have a look.
It does a very small and neat task. With this, my earlier statement gets converted to the below.
ResultCheck rCheck = ITK_ok;
try
{
rCheck = AOM_ask_value_logical( myTag, "attributeName", &attributeValue);
}
catch (const IFail &ex)
{
// DO SOMETHING
}
With every function call return statement, an instance of ResultCheck
is created. If you check the header file, you would see overloaded assignment operator takes an ifail
(integer) as an input. Internally it checks if ifail
is ITK_ok
or not. If it is not, then it simply throws IFail
. And control is passed to you in catch block to do anything you want to do.
Simple isn’t it? So let’s now remove all these macros and use this…