Using ACE try macros for CORBA programming

CORBA::Environment provides a way for exception handling when native c++ exception handling is unavailable or undesirable. However, writing portable code for both (with and without) native exception handling capability is very hairy.

ACE provides a set of macros to help dealing with the chaos, but please keep in mind that no amount of macros is going to solve the problem perfectly.

In a Nutshell

This section explains some simple rules of writing programs for platforms with and without native exception support using ACE's try macros.

  1. ACE try macros are modeled and used like native c++ exceptions with some extra rules to ensure it works even on platforms without native exception support. See some quick examples about how to use ACE try macros.

  2. Name of CORBA::Environment variable
    A function that may throw a CORBA::Exception needs a CORBA::Environment variable to pass up exceptions and to gather exceptions from functions it called. By default, ACE try macros assume the variable is named ACE_TRY_ENV. ACE_TRY_ENV itself is also a macro which can be redefined. If you are using TAO, more likely than not, you don't have to worry about redefining this macro because TAO is written to use ACE try macros. For example, you should define your functions as,

          int AN_OBJ::foobar (int a, int b, CORBA_Environment &ACE_TRY_ENV);
          

    and within the function, call other functions that might throw exceptions like,

          another_obj->func_name (x, y, ACE_TRY_ENV);
          

    As mentioned, you can redefine the name of the variable to something else to avoid name clashing. Alternatively, there's another macro (ACE_ADOPT_CORBA_ENV) that allow you to use another variable name as the default CORBA::Environment within a function.

  3. Throwing exceptions:
    Use ACE_THROW and ACE_THROW_RETURN to throw exceptions. They should never be used withing a try block; please use ACE_TRY_THROW instead.

  4. Propagating exceptions:
    To simulate native exceptions on platforms without native exception handling, every single function call that may throw exceptions must be followed by ACE_CHECK or ACE_CHECK_RETURN.

    Exception-throwing functions include the following categories:

    1. Any function that takes a CORBA_Environment variable.

    2. ACE_NEW_THROW_EX. Notice that you should not use ACE_NEW_THROW, ACE_NEW_THROW_RETURN, ACE_NEW_TRY_THROW anymore because they don't work right with ACE try macros. Instead, use ACE_NEW_THROW with appropriate ACE_CHECK* macros.

    3. ACE_TRY blocks. Follow every ACE_ENDTRY with appropriate ACE_CHECK* macros.

    Notice that you should always follow the outter most ACE_ENDTRY with ACE_CHECK or ACE_CHECK_RETURN because there might be uncaught exception.

    You should pass ACE_TRY_ENV to these functions.

    Be very careful not to combine exception throwing functions in one statement like this:

              x = obj1->callme (ACE_TRY_ENV) + obj2->dare_me (ACE_TRY_ENV);
              ACE_CHECK;
          

    This example may work differently when native exception handling is enabled/disabled.

  5. Catching exceptions:
    Use ACE_TRY to catch exceptions if there's an ACE_TRY_ENV available. Otherwise, you should use ACE_DECLARE_NEW_CORBA_ENV to create one at proper scope. The use of ACE_TRY_NEW_ENV is considered depricated because it can't deal with the case when you have multiple TRY blocks in the scope of ACE_TRY_NEW_ENV. If there are more than one try blocks in a function, use ACE_TRY_EX for all subsequence try blocks to avoid name clashing of labels.

  6. Printing out exceptions. Use ACE_PRINT_EXCEPTION (EX,INFO) to print out an exception. The macro takes two arguments, a reference to an exception (EX) and a char * string (INFO) which provides more information on the exception. Since there's no portable way to print out exceptions, you can redefine ACE_PRINT_EXCEPTION to fit your need (or define it to null.) You should always print out the exception itself, not the CORBA_Environment that carries the exception.

Examples

Refer to $ACE_ROOT/ace/CORBA_macros.h for complete definitions of macros discussed here.

General Guidelines of Exceptions

Caveats

As we already mentioned no set of macros can cover all cases and preserve the semantics between native C++ exceptions and the CORBA::Environment based mapping. Some of the problems that our macros are described below:

Transition from TAO try macros to ACE try macros

This list tries to give a comprehensive list of mapping between TAO try macros and ACE try macros. It's sole purpose is to provide hints in the converting the use of TAO try macros to ACE try macros and is by no mean complete.
  1. Rename all CORBA_Environment variables to ACE_TRY_ENV.

  2. Replace TAO_TRY TAO_TRY_VAR with ACE_TRY. Added ACE_DECLARE_NEW_CORBA_ENV if necessary.

  3. Replace TAO_TRY_EX TAO_TRY_VAR_EX with ACE_TRY_EX.

  4. Replace TAO_CHECK_RETURN and TAO_CHECK_RETURN_VOID with ACE_CHECK_RETURN and ACE_CHECK. These macros are used outside of TRY/CATCH blocks.

  5. Replace TAO_THROW, TAO_THROW_ENV, TAO_THROW_RETURN, TAO_THROW_ENV_RETURN with ACE_THROW and ACE_THROW_RETURN.

  6. Replace TAO_CHECK_ENV and TAO_CHECK_ENV_EX with ACE_TRY_CHECK and ACE_TRY_CHECK_EX.

  7. Replace TAO_TRY_THOW and TAO_TRY_THROW_EX with ACE_TRY_THROW and ACE_TRY_THROW_EX. Notice that you can also use ACE_TRY_THROW* within CATCH blocks.

  8. Replace TAO_RETHROW, TAO_RETHROW_RETURN, TAO_RETHROW_RETURN_VOID with ACE_RETHROW.

  9. Replace TAO_CATCH, TAO_CATCHANY, and TAO_CATCHALL with ACE_CATCH, ACE_CATCHANY and ACE_CATCHALL respectively.

  10. Replace TAO_ENDTRY with ACE_ENDTRY followed by an appropriate CHECK macro (ACE_CHECK, ACE_CHECK_RETURN, ACE_TRY_CHECK, or ACE_TRY_CHECK_EX.)